source: trunk/src/activeqt/control/qaxserverbase.cpp@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 122.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the ActiveQt framework of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:BSD$
10** You may use this file under the terms of the BSD license as follows:
11**
12** "Redistribution and use in source and binary forms, with or without
13** modification, are permitted provided that the following conditions are
14** met:
15** * Redistributions of source code must retain the above copyright
16** notice, this list of conditions and the following disclaimer.
17** * Redistributions in binary form must reproduce the above copyright
18** notice, this list of conditions and the following disclaimer in
19** the documentation and/or other materials provided with the
20** distribution.
21** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22** the names of its contributors may be used to endorse or promote
23** products derived from this software without specific prior written
24** permission.
25**
26** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#define QT_NO_CAST_TO_ASCII
42
43#ifndef QT_NO_WIN_ACTIVEQT
44
45#include <qabstracteventdispatcher.h>
46#include <qapplication.h>
47#include <qbuffer.h>
48#include <qdatastream.h>
49#include <qdebug.h>
50#include <qevent.h>
51#include <qeventloop.h>
52#include <qfile.h>
53#include <qpointer.h>
54#include <qhash.h>
55#include <qmap.h>
56#include <qmenubar.h>
57#include <qmenu.h>
58#include <qmetaobject.h>
59#include <qpixmap.h>
60#include <qstatusbar.h>
61#include <qwhatsthis.h>
62#include <ocidl.h>
63#include <olectl.h>
64#include <private/qcoreapplication_p.h>
65
66#include "qaxfactory.h"
67#include "qaxbindable.h"
68#include "qaxaggregated.h"
69
70#include "../shared/qaxtypes.h"
71
72#if defined Q_CC_GNU
73# include <w32api.h>
74#endif
75
76#ifndef Q_OS_WIN64
77#define ULONG_PTR DWORD
78#endif
79
80QT_BEGIN_NAMESPACE
81
82extern HHOOK qax_hhook;
83
84// in qaxserver.cpp
85extern ITypeLib *qAxTypeLibrary;
86extern QAxFactory *qAxFactory();
87extern unsigned long qAxLock();
88extern unsigned long qAxUnlock();
89extern HANDLE qAxInstance;
90extern bool qAxOutProcServer;
91
92static int invokeCount = 0;
93
94#ifdef QT_DEBUG
95unsigned long qaxserverbase_instance_count = 0;
96#endif
97
98// in qaxserverdll.cpp
99extern bool qax_ownQApp;
100
101struct QAxExceptInfo
102{
103 QAxExceptInfo(int c, const QString &s, const QString &d, const QString &x)
104 : code(c), src(s), desc(d), context(x)
105 {
106 }
107 int code;
108 QString src;
109 QString desc;
110 QString context;
111};
112
113
114bool qt_sendSpontaneousEvent(QObject*, QEvent*);
115
116/*
117 \class QAxServerBase
118 \brief The QAxServerBase class is an ActiveX control hosting a QWidget.
119
120 \internal
121*/
122class QAxServerBase :
123 public QObject,
124 public IAxServerBase,
125 public IDispatch,
126 public IOleObject,
127 public IOleControl,
128#if defined Q_CC_GNU
129# if (__W32API_MAJOR_VERSION < 2 || (__W32API_MAJOR_VERSION == 2 && __W32API_MINOR_VERSION < 5))
130 public IViewObject, // this should not be needed as IViewObject2 is meant to inherit from this,
131 // untill the mingw headers are fixed this will need to stay.
132# endif
133#endif
134 public IViewObject2,
135 public IOleInPlaceObject,
136 public IOleInPlaceActiveObject,
137 public IProvideClassInfo2,
138 public IConnectionPointContainer,
139 public IPersistStream,
140 public IPersistStreamInit,
141 public IPersistStorage,
142 public IPersistPropertyBag,
143 public IPersistFile,
144 public IDataObject
145{
146public:
147 typedef QMap<QUuid,IConnectionPoint*> ConnectionPoints;
148 typedef QMap<QUuid,IConnectionPoint*>::Iterator ConnectionPointsIterator;
149
150 QAxServerBase(const QString &classname, IUnknown *outerUnknown);
151 QAxServerBase(QObject *o);
152
153 void init();
154
155 ~QAxServerBase();
156
157// Window creation
158 HWND create(HWND hWndParent, RECT& rcPos);
159 HMENU createPopup(QMenu *popup, HMENU oldMenu = 0);
160 void createMenu(QMenuBar *menuBar);
161 void removeMenu();
162
163 static LRESULT QT_WIN_CALLBACK ActiveXProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
164
165// Object registration with OLE
166 void registerActiveObject(IUnknown *object);
167 void revokeActiveObject();
168
169// IUnknown
170 unsigned long WINAPI AddRef()
171 {
172 if (m_outerUnknown)
173 return m_outerUnknown->AddRef();
174
175 EnterCriticalSection(&refCountSection);
176 unsigned long r = ++ref;
177 LeaveCriticalSection(&refCountSection);
178
179 return r;
180 }
181 unsigned long WINAPI Release()
182 {
183 if (m_outerUnknown)
184 return m_outerUnknown->Release();
185
186 EnterCriticalSection(&refCountSection);
187 unsigned long r = --ref;
188 LeaveCriticalSection(&refCountSection);
189
190 if (!r) {
191 delete this;
192 return 0;
193 }
194 return r;
195 }
196 HRESULT WINAPI QueryInterface(REFIID iid, void **iface);
197 HRESULT InternalQueryInterface(REFIID iid, void **iface);
198
199// IAxServerBase
200 IUnknown *clientSite() const
201 {
202 return m_spClientSite;
203 }
204
205 void emitPropertyChanged(const char*);
206 bool emitRequestPropertyChange(const char*);
207 QObject *qObject() const
208 {
209 return theObject;
210 }
211 void ensureMetaData();
212 bool isPropertyExposed(int index);
213
214 void reportError(int code, const QString &src, const QString &desc, const QString &context)
215 {
216 if (exception)
217 delete exception;
218 exception = new QAxExceptInfo(code, src, desc, context);
219 }
220
221// IDispatch
222 STDMETHOD(GetTypeInfoCount)(UINT* pctinfo);
223 STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
224 STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid);
225 STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
226 LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
227 EXCEPINFO* pexcepinfo, UINT* puArgErr);
228
229// IProvideClassInfo
230 STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo);
231
232// IProvideClassInfo2
233 STDMETHOD(GetGUID)(DWORD dwGuidKind, GUID* pGUID);
234
235// IOleObject
236 STDMETHOD(Advise)(IAdviseSink* pAdvSink, DWORD* pdwConnection);
237 STDMETHOD(Close)(DWORD dwSaveOption);
238 STDMETHOD(DoVerb)(LONG iVerb, LPMSG lpmsg, IOleClientSite* pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect);
239 STDMETHOD(EnumAdvise)(IEnumSTATDATA** ppenumAdvise);
240 STDMETHOD(EnumVerbs)(IEnumOLEVERB** ppEnumOleVerb);
241 STDMETHOD(GetClientSite)(IOleClientSite** ppClientSite);
242 STDMETHOD(GetClipboardData)(DWORD dwReserved, IDataObject** ppDataObject);
243 STDMETHOD(GetExtent)(DWORD dwDrawAspect, SIZEL* psizel);
244 STDMETHOD(GetMiscStatus)(DWORD dwAspect, DWORD *pdwStatus);
245 STDMETHOD(GetMoniker)(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk);
246 STDMETHOD(GetUserClassID)(CLSID* pClsid);
247 STDMETHOD(GetUserType)(DWORD dwFormOfType, LPOLESTR *pszUserType);
248 STDMETHOD(InitFromData)(IDataObject* pDataObject, BOOL fCreation, DWORD dwReserved);
249 STDMETHOD(IsUpToDate)();
250 STDMETHOD(SetClientSite)(IOleClientSite* pClientSite);
251 STDMETHOD(SetColorScheme)(LOGPALETTE* pLogPal);
252 STDMETHOD(SetExtent)(DWORD dwDrawAspect, SIZEL* psizel);
253 STDMETHOD(SetHostNames)(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj);
254 STDMETHOD(SetMoniker)(DWORD dwWhichMoniker, IMoniker* ppmk);
255 STDMETHOD(Unadvise)(DWORD dwConnection);
256 STDMETHOD(Update)();
257
258// IViewObject
259 STDMETHOD(Draw)(DWORD dwAspect, LONG lIndex, void *pvAspect, DVTARGETDEVICE *ptd,
260 HDC hicTargetDevice, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
261 BOOL(__stdcall*pfnContinue)(ULONG_PTR), ULONG_PTR dwContinue);
262 STDMETHOD(GetColorSet)(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
263 HDC hicTargetDev, LOGPALETTE **ppColorSet);
264 STDMETHOD(Freeze)(DWORD dwAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze);
265 STDMETHOD(Unfreeze)(DWORD dwFreeze);
266 STDMETHOD(SetAdvise)(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink);
267 STDMETHOD(GetAdvise)(DWORD *aspects, DWORD *advf, IAdviseSink **pAdvSink);
268
269// IViewObject2
270 STDMETHOD(GetExtent)(DWORD dwAspect, LONG lindex, DVTARGETDEVICE *ptd, LPSIZEL lpsizel);
271
272// IOleControl
273 STDMETHOD(FreezeEvents)(BOOL);
274 STDMETHOD(GetControlInfo)(LPCONTROLINFO);
275 STDMETHOD(OnAmbientPropertyChange)(DISPID);
276 STDMETHOD(OnMnemonic)(LPMSG);
277
278// IOleWindow
279 STDMETHOD(GetWindow)(HWND *pHwnd);
280 STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode);
281
282// IOleInPlaceObject
283 STDMETHOD(InPlaceDeactivate)();
284 STDMETHOD(UIDeactivate)();
285 STDMETHOD(SetObjectRects)(LPCRECT lprcPosRect, LPCRECT lprcClipRect);
286 STDMETHOD(ReactivateAndUndo)();
287
288// IOleInPlaceActiveObject
289 STDMETHOD(TranslateAcceleratorW)(MSG *pMsg);
290 STDMETHOD(TranslateAcceleratorA)(MSG *pMsg);
291 STDMETHOD(OnFrameWindowActivate)(BOOL);
292 STDMETHOD(OnDocWindowActivate)(BOOL fActivate);
293 STDMETHOD(ResizeBorder)(LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fFrameWindow);
294 STDMETHOD(EnableModeless)(BOOL);
295
296// IConnectionPointContainer
297 STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints**);
298 STDMETHOD(FindConnectionPoint)(REFIID, IConnectionPoint**);
299
300// IPersist
301 STDMETHOD(GetClassID)(GUID*clsid)
302 {
303 *clsid = qAxFactory()->classID(class_name);
304 return S_OK;
305 }
306
307// IPersistStreamInit
308 STDMETHOD(InitNew)(VOID);
309 STDMETHOD(IsDirty)();
310 STDMETHOD(Load)(IStream *pStm);
311 STDMETHOD(Save)(IStream *pStm, BOOL fClearDirty);
312 STDMETHOD(GetSizeMax)(ULARGE_INTEGER *pcbSize);
313
314// IPersistPropertyBag
315 STDMETHOD(Load)(IPropertyBag *, IErrorLog *);
316 STDMETHOD(Save)(IPropertyBag *, BOOL, BOOL);
317
318// IPersistStorage
319 STDMETHOD(InitNew)(IStorage *pStg);
320 STDMETHOD(Load)(IStorage *pStg);
321 STDMETHOD(Save)(IStorage *pStg, BOOL fSameAsLoad);
322 STDMETHOD(SaveCompleted)(IStorage *pStgNew);
323 STDMETHOD(HandsOffStorage)();
324
325// IPersistFile
326 STDMETHOD(SaveCompleted)(LPCOLESTR fileName);
327 STDMETHOD(GetCurFile)(LPOLESTR *currentFile);
328 STDMETHOD(Load)(LPCOLESTR fileName, DWORD mode);
329 STDMETHOD(Save)(LPCOLESTR fileName, BOOL fRemember);
330
331// IDataObject
332 STDMETHOD(GetData)(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
333 STDMETHOD(GetDataHere)(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */);
334 STDMETHOD(QueryGetData)(FORMATETC* /* pformatetc */);
335 STDMETHOD(GetCanonicalFormatEtc)(FORMATETC* /* pformatectIn */,FORMATETC* /* pformatetcOut */);
336 STDMETHOD(SetData)(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */, BOOL /* fRelease */);
337 STDMETHOD(EnumFormatEtc)(DWORD /* dwDirection */, IEnumFORMATETC** /* ppenumFormatEtc */);
338 STDMETHOD(DAdvise)(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
339 STDMETHOD(DUnadvise)(DWORD dwConnection);
340 STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise);
341
342// QObject
343 int qt_metacall(QMetaObject::Call, int index, void **argv);
344
345 bool eventFilter(QObject *o, QEvent *e);
346private:
347 void update();
348 void resize(const QSize &newSize);
349 void updateGeometry();
350 void updateMask();
351 bool internalCreate();
352 void internalBind();
353 void internalConnect();
354 HRESULT internalActivate();
355
356 friend class QAxBindable;
357 friend class QAxPropertyPage;
358
359 QAxAggregated *aggregatedObject;
360 ConnectionPoints points;
361
362 union {
363 QWidget *widget;
364 QObject *object;
365 } qt;
366 QPointer<QObject> theObject;
367 unsigned isWidget :1;
368 unsigned ownObject :1;
369 unsigned initNewCalled :1;
370 unsigned dirtyflag :1;
371 unsigned hasStockEvents :1;
372 unsigned stayTopLevel :1;
373 unsigned isInPlaceActive :1;
374 unsigned isUIActive :1;
375 unsigned wasUIActive :1;
376 unsigned inDesignMode :1;
377 unsigned canTakeFocus :1;
378 short freezeEvents;
379
380 HWND m_hWnd;
381
382 HMENU hmenuShared;
383 HOLEMENU holemenu;
384 HWND hwndMenuOwner;
385 QMap<HMENU, QMenu*> menuMap;
386 QMap<UINT, QAction*> actionMap;
387 QPointer<QMenuBar> menuBar;
388 QPointer<QStatusBar> statusBar;
389 QPointer<QMenu> currentPopup;
390 QAxExceptInfo *exception;
391
392 CRITICAL_SECTION refCountSection;
393 CRITICAL_SECTION createWindowSection;
394
395 unsigned long ref;
396 unsigned long ole_ref;
397
398 QString class_name;
399 QString currentFileName;
400
401 QHash<long, int> indexCache;
402 QHash<int,DISPID> signalCache;
403
404 IUnknown *m_outerUnknown;
405 IAdviseSink *m_spAdviseSink;
406 QList<STATDATA> adviseSinks;
407 IOleClientSite *m_spClientSite;
408 IOleInPlaceSiteWindowless *m_spInPlaceSite;
409 IOleInPlaceFrame *m_spInPlaceFrame;
410 ITypeInfo *m_spTypeInfo;
411 IStorage *m_spStorage;
412 QSize m_currentExtent;
413};
414
415class QAxServerAggregate : public IUnknown
416{
417public:
418 QAxServerAggregate(const QString &className, IUnknown *outerUnknown)
419 : m_outerUnknown(outerUnknown), ref(0)
420 {
421 object = new QAxServerBase(className, outerUnknown);
422 object->registerActiveObject(this);
423
424 InitializeCriticalSection(&refCountSection);
425 InitializeCriticalSection(&createWindowSection);
426 }
427 ~QAxServerAggregate()
428 {
429 DeleteCriticalSection(&refCountSection);
430 DeleteCriticalSection(&createWindowSection);
431
432 delete object;
433 }
434
435// IUnknown
436 unsigned long WINAPI AddRef()
437 {
438 EnterCriticalSection(&refCountSection);
439 unsigned long r = ++ref;
440 LeaveCriticalSection(&refCountSection);
441
442 return r;
443 }
444 unsigned long WINAPI Release()
445 {
446 EnterCriticalSection(&refCountSection);
447 unsigned long r = --ref;
448 LeaveCriticalSection(&refCountSection);
449
450 if (!r) {
451 delete this;
452 return 0;
453 }
454 return r;
455 }
456 HRESULT WINAPI QueryInterface(REFIID iid, void **iface)
457 {
458 *iface = 0;
459
460 HRESULT res = E_NOINTERFACE;
461 if (iid == IID_IUnknown) {
462 *iface = (IUnknown*)this;
463 AddRef();
464 return S_OK;
465 }
466 return object->InternalQueryInterface(iid, iface);
467 }
468
469private:
470 QAxServerBase *object;
471 IUnknown *m_outerUnknown;
472 unsigned long ref;
473
474 CRITICAL_SECTION refCountSection;
475 CRITICAL_SECTION createWindowSection;
476};
477
478bool QAxFactory::createObjectWrapper(QObject *object, IDispatch **wrapper)
479{
480 *wrapper = 0;
481 QAxServerBase *obj = new QAxServerBase(object);
482 obj->QueryInterface(IID_IDispatch, (void**)wrapper);
483 if (*wrapper)
484 return true;
485
486 delete obj;
487 return false;
488}
489
490
491/*
492 Helper class to enumerate all supported event interfaces.
493*/
494class QAxSignalVec : public IEnumConnectionPoints
495{
496public:
497 QAxSignalVec(const QAxServerBase::ConnectionPoints &points)
498 : cpoints(points), ref(0)
499 {
500 InitializeCriticalSection(&refCountSection);
501 for (QAxServerBase::ConnectionPointsIterator i = cpoints.begin(); i != cpoints.end(); ++i)
502 (*i)->AddRef();
503 }
504 QAxSignalVec(const QAxSignalVec &old)
505 {
506 InitializeCriticalSection(&refCountSection);
507 ref = 0;
508 cpoints = old.cpoints;
509 for (QAxServerBase::ConnectionPointsIterator i = cpoints.begin(); i != cpoints.end(); ++i)
510 (*i)->AddRef();
511 it = old.it;
512 }
513 ~QAxSignalVec()
514 {
515 for (QAxServerBase::ConnectionPointsIterator i = cpoints.begin(); i != cpoints.end(); ++i)
516 (*i)->Release();
517
518 DeleteCriticalSection(&refCountSection);
519 }
520
521 unsigned long __stdcall AddRef()
522 {
523 EnterCriticalSection(&refCountSection);
524 unsigned long r = ++ref;
525 LeaveCriticalSection(&refCountSection);
526 return ++r;
527 }
528 unsigned long __stdcall Release()
529 {
530 EnterCriticalSection(&refCountSection);
531 unsigned long r = --ref;
532 LeaveCriticalSection(&refCountSection);
533
534 if (!r) {
535 delete this;
536 return 0;
537 }
538 return r;
539 }
540 STDMETHOD(QueryInterface)(REFIID iid, void **iface)
541 {
542 *iface = 0;
543 if (iid == IID_IUnknown)
544 *iface = this;
545 else if (iid == IID_IEnumConnectionPoints)
546 *iface = this;
547 else
548 return E_NOINTERFACE;
549
550 AddRef();
551 return S_OK;
552 }
553 STDMETHOD(Next)(ULONG cConnections, IConnectionPoint **cpoint, ULONG *pcFetched)
554 {
555 unsigned long i;
556 for (i = 0; i < cConnections; i++) {
557 if (it == cpoints.end())
558 break;
559 IConnectionPoint *cp = *it;
560 cp->AddRef();
561 cpoint[i] = cp;
562 ++it;
563 }
564 *pcFetched = i;
565 return i == cConnections ? S_OK : S_FALSE;
566 }
567 STDMETHOD(Skip)(ULONG cConnections)
568 {
569 while (cConnections) {
570 ++it;
571 --cConnections;
572 if (it == cpoints.end())
573 return S_FALSE;
574 }
575 return S_OK;
576 }
577 STDMETHOD(Reset)()
578 {
579 it = cpoints.begin();
580
581 return S_OK;
582 }
583 STDMETHOD(Clone)(IEnumConnectionPoints **ppEnum)
584 {
585 *ppEnum = new QAxSignalVec(*this);
586 (*ppEnum)->AddRef();
587
588 return S_OK;
589 }
590
591 QAxServerBase::ConnectionPoints cpoints;
592 QAxServerBase::ConnectionPointsIterator it;
593
594private:
595 CRITICAL_SECTION refCountSection;
596
597 unsigned long ref;
598};
599
600/*
601 Helper class to store and enumerate all connected event listeners.
602*/
603class QAxConnection : public IConnectionPoint,
604 public IEnumConnections
605{
606public:
607 typedef QList<CONNECTDATA> Connections;
608 typedef QList<CONNECTDATA>::Iterator Iterator;
609
610 QAxConnection(QAxServerBase *parent, const QUuid &uuid)
611 : that(parent), iid(uuid), ref(1)
612 {
613 InitializeCriticalSection(&refCountSection);
614 }
615 QAxConnection(const QAxConnection &old)
616 {
617 InitializeCriticalSection(&refCountSection);
618 ref = 0;
619 connections = old.connections;
620 it = old.it;
621 that = old.that;
622 iid = old.iid;
623 QList<CONNECTDATA>::Iterator it = connections.begin();
624 while (it != connections.end()) {
625 CONNECTDATA connection = *it;
626 ++it;
627 connection.pUnk->AddRef();
628 }
629 }
630 ~QAxConnection()
631 {
632 DeleteCriticalSection(&refCountSection);
633 }
634
635 unsigned long __stdcall AddRef()
636 {
637 EnterCriticalSection(&refCountSection);
638 unsigned long r = ++ref;
639 LeaveCriticalSection(&refCountSection);
640 return r;
641 }
642 unsigned long __stdcall Release()
643 {
644 EnterCriticalSection(&refCountSection);
645 unsigned long r = --ref;
646 LeaveCriticalSection(&refCountSection);
647
648 if (!r) {
649 delete this;
650 return 0;
651 }
652 return r;
653 }
654 STDMETHOD(QueryInterface)(REFIID iid, void **iface)
655 {
656 *iface = 0;
657 if (iid == IID_IUnknown)
658 *iface = (IConnectionPoint*)this;
659 else if (iid == IID_IConnectionPoint)
660 *iface = this;
661 else if (iid == IID_IEnumConnections)
662 *iface = this;
663 else
664 return E_NOINTERFACE;
665
666 AddRef();
667 return S_OK;
668 }
669 STDMETHOD(GetConnectionInterface)(IID *pIID)
670 {
671 *pIID = iid;
672 return S_OK;
673 }
674 STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer **ppCPC)
675 {
676 return that->QueryInterface(IID_IConnectionPointContainer, (void**)ppCPC);
677 }
678 STDMETHOD(Advise)(IUnknown*pUnk, DWORD *pdwCookie)
679 {
680 {
681 IDispatch *checkImpl = 0;
682 pUnk->QueryInterface(iid, (void**)&checkImpl);
683 if (!checkImpl)
684 return CONNECT_E_CANNOTCONNECT;
685 checkImpl->Release();
686 }
687
688 CONNECTDATA cd;
689 cd.dwCookie = connections.count()+1;
690 cd.pUnk = pUnk;
691 cd.pUnk->AddRef();
692 connections.append(cd);
693
694 *pdwCookie = cd.dwCookie;
695 return S_OK;
696 }
697 STDMETHOD(Unadvise)(DWORD dwCookie)
698 {
699 QList<CONNECTDATA>::Iterator it = connections.begin();
700 while (it != connections.end()) {
701 CONNECTDATA cd = *it;
702 if (cd.dwCookie == dwCookie) {
703 cd.pUnk->Release();
704 connections.erase(it);
705 return S_OK;
706 }
707 ++it;
708 }
709 return CONNECT_E_NOCONNECTION;
710 }
711 STDMETHOD(EnumConnections)(IEnumConnections **ppEnum)
712 {
713 *ppEnum = this;
714 AddRef();
715
716 return S_OK;
717 }
718 STDMETHOD(Next)(ULONG cConnections, CONNECTDATA *cd, ULONG *pcFetched)
719 {
720 unsigned long i;
721 for (i = 0; i < cConnections; i++) {
722 if (it == connections.end())
723 break;
724 cd[i] = *it;
725 cd[i].pUnk->AddRef();
726 ++it;
727 }
728 if (pcFetched)
729 *pcFetched = i;
730 return i == cConnections ? S_OK : S_FALSE;
731 }
732 STDMETHOD(Skip)(ULONG cConnections)
733 {
734 while (cConnections) {
735 ++it;
736 --cConnections;
737 if (it == connections.end())
738 return S_FALSE;
739 }
740 return S_OK;
741 }
742 STDMETHOD(Reset)()
743 {
744 it = connections.begin();
745
746 return S_OK;
747 }
748 STDMETHOD(Clone)(IEnumConnections **ppEnum)
749 {
750 *ppEnum = new QAxConnection(*this);
751 (*ppEnum)->AddRef();
752
753 return S_OK;
754 }
755
756private:
757 QAxServerBase *that;
758 QUuid iid;
759 Connections connections;
760 Iterator it;
761
762 CRITICAL_SECTION refCountSection;
763 unsigned long ref;
764};
765
766// callback for DLL server to hook into non-Qt eventloop
767LRESULT QT_WIN_CALLBACK axs_FilterProc(int nCode, WPARAM wParam, LPARAM lParam)
768{
769 if (qApp && !invokeCount)
770 qApp->sendPostedEvents();
771
772 return CallNextHookEx(qax_hhook, nCode, wParam, lParam);
773}
774
775// filter for executable case to hook into Qt eventloop
776// for DLLs the client calls TranslateAccelerator
777bool qax_winEventFilter(void *message)
778{
779 MSG *pMsg = (MSG*)message;
780 if (pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST)
781 return false;
782
783 bool ret = false;
784 QWidget *aqt = QWidget::find(pMsg->hwnd);
785 if (!aqt)
786 return ret;
787
788 HWND baseHwnd = ::GetParent(aqt->winId());
789 QAxServerBase *axbase = 0;
790 while (!axbase && baseHwnd) {
791#ifdef GWLP_USERDATA
792 axbase = (QAxServerBase*)GetWindowLongPtr(baseHwnd, GWLP_USERDATA);
793#else
794 axbase = (QAxServerBase*)GetWindowLong(baseHwnd, GWL_USERDATA);
795#endif
796
797 baseHwnd = ::GetParent(baseHwnd);
798 }
799 if (!axbase)
800 return ret;
801
802 HRESULT hres = axbase->TranslateAcceleratorW(pMsg);
803 return hres == S_OK;
804}
805
806extern void qWinMsgHandler(QtMsgType t, const char* str);
807
808// COM Factory class, mapping COM requests to ActiveQt requests.
809// One instance of this class for each ActiveX the server can provide.
810class QClassFactory : public IClassFactory2
811{
812public:
813 QClassFactory(CLSID clsid)
814 : ref(0), licensed(false)
815 {
816 InitializeCriticalSection(&refCountSection);
817
818 // COM only knows the CLSID, but QAxFactory is class name based...
819 QStringList keys = qAxFactory()->featureList();
820 for (QStringList::Iterator key = keys.begin(); key != keys.end(); ++key) {
821 if (qAxFactory()->classID(*key) == clsid) {
822 className = *key;
823 break;
824 }
825 }
826
827 const QMetaObject *mo = qAxFactory()->metaObject(className);
828 if (mo) {
829 classKey = QLatin1String(mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value());
830 licensed = !classKey.isEmpty();
831 }
832 }
833
834 ~QClassFactory()
835 {
836 DeleteCriticalSection(&refCountSection);
837 }
838
839 // IUnknown
840 unsigned long WINAPI AddRef()
841 {
842 EnterCriticalSection(&refCountSection);
843 unsigned long r = ++ref;
844 LeaveCriticalSection(&refCountSection);
845 return ++r;
846 }
847 unsigned long WINAPI Release()
848 {
849 EnterCriticalSection(&refCountSection);
850 unsigned long r = --ref;
851 LeaveCriticalSection(&refCountSection);
852
853 if (!r) {
854 delete this;
855 return 0;
856 }
857 return r;
858 }
859 HRESULT WINAPI QueryInterface(REFIID iid, LPVOID *iface)
860 {
861 *iface = 0;
862 if (iid == IID_IUnknown)
863 *iface = (IUnknown*)this;
864 else if (iid == IID_IClassFactory)
865 *iface = (IClassFactory*)this;
866 else if (iid == IID_IClassFactory2 && licensed)
867 *iface = (IClassFactory2*)this;
868 else
869 return E_NOINTERFACE;
870
871 AddRef();
872 return S_OK;
873 }
874
875 HRESULT WINAPI CreateInstanceHelper(IUnknown *pUnkOuter, REFIID iid, void **ppObject)
876 {
877 if (pUnkOuter) {
878 if (iid != IID_IUnknown)
879 return CLASS_E_NOAGGREGATION;
880 const QMetaObject *mo = qAxFactory()->metaObject(className);
881 if (mo && !qstricmp(mo->classInfo(mo->indexOfClassInfo("Aggregatable")).value(), "no"))
882 return CLASS_E_NOAGGREGATION;
883 }
884
885 // Make sure a QApplication instance is present (inprocess case)
886 if (!qApp) {
887 qInstallMsgHandler(qWinMsgHandler);
888 qax_ownQApp = true;
889 int argc = 0;
890 QApplication *app = new QApplication(argc, 0);
891 }
892 qApp->setQuitOnLastWindowClosed(false);
893
894 if (qAxOutProcServer)
895 QAbstractEventDispatcher::instance()->setEventFilter(qax_winEventFilter);
896 else
897 QApplication::instance()->d_func()->in_exec = true;
898
899 // hook into eventloop; this allows a server to create his own QApplication object
900 if (!qax_hhook && qax_ownQApp) {
901 qax_hhook = SetWindowsHookEx(WH_GETMESSAGE, axs_FilterProc, 0, GetCurrentThreadId());
902 }
903
904 HRESULT res;
905 // Create the ActiveX wrapper - aggregate if requested
906 if (pUnkOuter) {
907 QAxServerAggregate *aggregate = new QAxServerAggregate(className, pUnkOuter);
908 res = aggregate->QueryInterface(iid, ppObject);
909 if (FAILED(res))
910 delete aggregate;
911 } else {
912 QAxServerBase *activeqt = new QAxServerBase(className, pUnkOuter);
913 res = activeqt->QueryInterface(iid, ppObject);
914 if (FAILED(res))
915 delete activeqt;
916 else
917 activeqt->registerActiveObject((IUnknown*)(IDispatch*)activeqt);
918 }
919 return res;
920 }
921
922 // IClassFactory
923 HRESULT WINAPI CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppObject)
924 {
925 // class is licensed
926 if (licensed && !qAxFactory()->validateLicenseKey(className, QString()))
927 return CLASS_E_NOTLICENSED;
928
929 return CreateInstanceHelper(pUnkOuter, iid, ppObject);
930 }
931 HRESULT WINAPI LockServer(BOOL fLock)
932 {
933 if (fLock)
934 qAxLock();
935 else
936 qAxUnlock();
937
938 return S_OK;
939 }
940
941 // IClassFactory2
942 HRESULT WINAPI RequestLicKey(DWORD, BSTR *pKey)
943 {
944 if (!pKey)
945 return E_POINTER;
946 *pKey = 0;
947
948 // This of course works only on fully licensed machines
949 if (!qAxFactory()->validateLicenseKey(className, QString()))
950 return CLASS_E_NOTLICENSED;
951
952 *pKey = QStringToBSTR(classKey);
953 return S_OK;
954 }
955
956 HRESULT WINAPI GetLicInfo(LICINFO *pLicInfo)
957 {
958 if (!pLicInfo)
959 return E_POINTER;
960 pLicInfo->cbLicInfo = sizeof(LICINFO);
961
962 // class specific license key?
963 const QMetaObject *mo = qAxFactory()->metaObject(className);
964 const char *key = mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value();
965 pLicInfo->fRuntimeKeyAvail = key && key[0];
966
967 // machine fully licensed?
968 pLicInfo->fLicVerified = qAxFactory()->validateLicenseKey(className, QString());
969
970 return S_OK;
971 }
972
973 HRESULT WINAPI CreateInstanceLic(IUnknown *pUnkOuter, IUnknown *pUnkReserved, REFIID iid, BSTR bKey, PVOID *ppObject)
974 {
975 QString licenseKey = QString::fromWCharArray(bKey);
976 if (!qAxFactory()->validateLicenseKey(className, licenseKey))
977 return CLASS_E_NOTLICENSED;
978 return CreateInstanceHelper(pUnkOuter, iid, ppObject);
979 }
980
981 QString className;
982
983protected:
984 CRITICAL_SECTION refCountSection;
985 unsigned long ref;
986 bool licensed;
987 QString classKey;
988};
989
990// Create a QClassFactory object for class \a iid
991HRESULT GetClassObject(REFIID clsid, REFIID iid, void **ppUnk)
992{
993 QClassFactory *factory = new QClassFactory(clsid);
994 if (!factory)
995 return E_OUTOFMEMORY;
996 if (factory->className.isEmpty()) {
997 delete factory;
998 return E_NOINTERFACE;
999 }
1000 HRESULT res = factory->QueryInterface(iid, ppUnk);
1001 if (res != S_OK)
1002 delete factory;
1003 return res;
1004}
1005
1006
1007/*!
1008 Constructs a QAxServerBase object wrapping the QWidget \a
1009 classname into an ActiveX control.
1010
1011 The constructor is called by the QClassFactory object provided by
1012 the COM server for the respective CLSID.
1013*/
1014QAxServerBase::QAxServerBase(const QString &classname, IUnknown *outerUnknown)
1015: aggregatedObject(0), ref(0), ole_ref(0), class_name(classname),
1016 m_hWnd(0), hmenuShared(0), hwndMenuOwner(0),
1017 m_outerUnknown(outerUnknown)
1018{
1019 init();
1020
1021 internalCreate();
1022}
1023
1024/*!
1025 Constructs a QAxServerBase object wrapping \a o.
1026*/
1027QAxServerBase::QAxServerBase(QObject *o)
1028: aggregatedObject(0), ref(0), ole_ref(0),
1029 m_hWnd(0), hmenuShared(0), hwndMenuOwner(0),
1030 m_outerUnknown(0)
1031{
1032 init();
1033
1034 qt.object = o;
1035 if (o) {
1036 theObject = o;
1037 isWidget = false;
1038 class_name = QLatin1String(o->metaObject()->className());
1039 }
1040 internalBind();
1041 internalConnect();
1042}
1043
1044/*!
1045 Initializes data members.
1046*/
1047void QAxServerBase::init()
1048{
1049 qt.object = 0;
1050 isWidget = false;
1051 ownObject = false;
1052 initNewCalled = false;
1053 dirtyflag = false;
1054 hasStockEvents = false;
1055 stayTopLevel = false;
1056 isInPlaceActive = false;
1057 isUIActive = false;
1058 wasUIActive = false;
1059 inDesignMode = false;
1060 canTakeFocus = false;
1061 freezeEvents = 0;
1062 exception = 0;
1063
1064 m_spAdviseSink = 0;
1065 m_spClientSite = 0;
1066 m_spInPlaceSite = 0;
1067 m_spInPlaceFrame = 0;
1068 m_spTypeInfo = 0;
1069 m_spStorage = 0;
1070
1071 InitializeCriticalSection(&refCountSection);
1072 InitializeCriticalSection(&createWindowSection);
1073
1074#ifdef QT_DEBUG
1075 EnterCriticalSection(&refCountSection);
1076 ++qaxserverbase_instance_count;
1077 LeaveCriticalSection(&refCountSection);
1078#endif
1079
1080 qAxLock();
1081
1082 points[IID_IPropertyNotifySink] = new QAxConnection(this, IID_IPropertyNotifySink);
1083}
1084
1085/*!
1086 Destroys the QAxServerBase object, releasing all allocated
1087 resources and interfaces.
1088*/
1089QAxServerBase::~QAxServerBase()
1090{
1091#ifdef QT_DEBUG
1092 EnterCriticalSection(&refCountSection);
1093 --qaxserverbase_instance_count;
1094 LeaveCriticalSection(&refCountSection);
1095#endif
1096
1097 revokeActiveObject();
1098
1099 for (QAxServerBase::ConnectionPointsIterator it = points.begin(); it != points.end(); ++it) {
1100 if (it.value())
1101 (*it)->Release();
1102 }
1103 delete aggregatedObject;
1104 aggregatedObject = 0;
1105 if (theObject) {
1106 qt.object->disconnect(this);
1107 QObject *aqt = qt.object;
1108 qt.object = 0;
1109 if (ownObject)
1110 delete aqt;
1111 }
1112
1113 if (m_spAdviseSink) m_spAdviseSink->Release();
1114 m_spAdviseSink = 0;
1115 for (int i = 0; i < adviseSinks.count(); ++i) {
1116 adviseSinks.at(i).pAdvSink->Release();
1117 }
1118 if (m_spClientSite) m_spClientSite->Release();
1119 m_spClientSite = 0;
1120 if (m_spInPlaceFrame) m_spInPlaceFrame->Release();
1121 m_spInPlaceFrame = 0;
1122 if (m_spInPlaceSite) m_spInPlaceSite->Release();
1123 m_spInPlaceSite = 0;
1124 if (m_spTypeInfo) m_spTypeInfo->Release();
1125 m_spTypeInfo = 0;
1126 if (m_spStorage) m_spStorage->Release();
1127 m_spStorage = 0;
1128
1129 DeleteCriticalSection(&refCountSection);
1130 DeleteCriticalSection(&createWindowSection);
1131
1132 qAxUnlock();
1133}
1134
1135/*
1136 Registering with OLE
1137*/
1138void QAxServerBase::registerActiveObject(IUnknown *object)
1139{
1140 if (ole_ref || !qt.object || !qAxOutProcServer)
1141 return;
1142
1143 const QMetaObject *mo = qt.object->metaObject();
1144 if (!qstricmp(mo->classInfo(mo->indexOfClassInfo("RegisterObject")).value(), "yes"))
1145 RegisterActiveObject(object, qAxFactory()->classID(class_name), ACTIVEOBJECT_WEAK, &ole_ref);
1146}
1147
1148void QAxServerBase::revokeActiveObject()
1149{
1150 if (!ole_ref)
1151 return;
1152
1153 RevokeActiveObject(ole_ref, 0);
1154 ole_ref = 0;
1155}
1156
1157/*
1158 QueryInterface implementation.
1159*/
1160HRESULT WINAPI QAxServerBase::QueryInterface(REFIID iid, void **iface)
1161{
1162 if (m_outerUnknown)
1163 return m_outerUnknown->QueryInterface(iid, iface);
1164
1165 return InternalQueryInterface(iid, iface);
1166}
1167
1168HRESULT QAxServerBase::InternalQueryInterface(REFIID iid, void **iface)
1169{
1170 *iface = 0;
1171
1172 if (iid == IID_IUnknown) {
1173 *iface = (IUnknown*)(IDispatch*)this;
1174 } else {
1175 HRESULT res = S_OK;
1176 if (aggregatedObject)
1177 res = aggregatedObject->queryInterface(iid, iface);
1178 if (*iface)
1179 return res;
1180 }
1181
1182 if (!(*iface)) {
1183 if (iid == qAxFactory()->interfaceID(class_name))
1184 *iface = (IDispatch*)this;
1185 if (iid == IID_IDispatch)
1186 *iface = (IDispatch*)this;
1187 else if (iid == IID_IAxServerBase)
1188 *iface = (IAxServerBase*)this;
1189 else if (iid == IID_IOleObject)
1190 *iface = (IOleObject*)this;
1191 else if (iid == IID_IConnectionPointContainer)
1192 *iface = (IConnectionPointContainer*)this;
1193 else if (iid == IID_IProvideClassInfo)
1194 *iface = (IProvideClassInfo*)this;
1195 else if (iid == IID_IProvideClassInfo2)
1196 *iface = (IProvideClassInfo2*)this;
1197 else if (iid == IID_IPersist)
1198 *iface = (IPersist*)(IPersistStream*)this;
1199 else if (iid == IID_IPersistStream)
1200 *iface = (IPersistStream*)this;
1201 else if (iid == IID_IPersistStreamInit)
1202 *iface = (IPersistStreamInit*)this;
1203 else if (iid == IID_IPersistStorage)
1204 *iface = (IPersistStorage*)this;
1205 else if (iid == IID_IPersistPropertyBag)
1206 *iface = (IPersistPropertyBag*)this;
1207 else if (iid == IID_IPersistFile &&
1208 qAxFactory()->metaObject(class_name)->indexOfClassInfo("MIME") != -1)
1209 *iface = (IPersistFile*)this;
1210 else if (iid == IID_IViewObject)
1211 *iface = (IViewObject*)this;
1212 else if (iid == IID_IViewObject2)
1213 *iface = (IViewObject2*)this;
1214 else if (isWidget) {
1215 if (iid == IID_IOleControl)
1216 *iface = (IOleControl*)this;
1217 else if (iid == IID_IOleWindow)
1218 *iface = (IOleWindow*)(IOleInPlaceObject*)this;
1219 else if (iid == IID_IOleInPlaceObject)
1220 *iface = (IOleInPlaceObject*)this;
1221 else if (iid == IID_IOleInPlaceActiveObject)
1222 *iface = (IOleInPlaceActiveObject*)this;
1223 else if (iid == IID_IDataObject)
1224 *iface = (IDataObject*)this;
1225 }
1226 }
1227 if (!*iface)
1228 return E_NOINTERFACE;
1229
1230 AddRef();
1231 return S_OK;
1232}
1233
1234/*!
1235 Detects and initilaizes implementation of QAxBindable in objects.
1236*/
1237void QAxServerBase::internalBind()
1238{
1239 QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable");
1240 if (axb) {
1241 // no addref; this is aggregated
1242 axb->activex = this;
1243 if (!aggregatedObject)
1244 aggregatedObject = axb->createAggregate();
1245 if (aggregatedObject) {
1246 aggregatedObject->controlling_unknown = (IUnknown*)(IDispatch*)this;
1247 aggregatedObject->the_object = qt.object;
1248 }
1249 }
1250}
1251
1252/*!
1253 Connects object signals to event dispatcher.
1254*/
1255void QAxServerBase::internalConnect()
1256{
1257 QUuid eventsID = qAxFactory()->eventsID(class_name);
1258 if (!eventsID.isNull()) {
1259 if (!points[eventsID])
1260 points[eventsID] = new QAxConnection(this, eventsID);
1261
1262 // connect the generic slot to all signals of qt.object
1263 const QMetaObject *mo = qt.object->metaObject();
1264 for (int isignal = mo->methodCount()-1; isignal >= 0; --isignal) {
1265 if (mo->method(isignal).methodType() == QMetaMethod::Signal)
1266 QMetaObject::connect(qt.object, isignal, this, isignal);
1267 }
1268 }
1269}
1270
1271/*!
1272 Creates the QWidget for the classname passed to the c'tor.
1273
1274 All signals of the widget class are connected to the internal event mapper.
1275 If the widget implements QAxBindable, stock events are also connected.
1276*/
1277bool QAxServerBase::internalCreate()
1278{
1279 if (qt.object)
1280 return true;
1281
1282 qt.object = qAxFactory()->createObject(class_name);
1283 Q_ASSERT(qt.object);
1284 if (!qt.object)
1285 return false;
1286
1287 theObject = qt.object;
1288 ownObject = true;
1289 isWidget = qt.object->isWidgetType();
1290 hasStockEvents = qAxFactory()->hasStockEvents(class_name);
1291 stayTopLevel = qAxFactory()->stayTopLevel(class_name);
1292
1293 internalBind();
1294 if (isWidget) {
1295 if (!stayTopLevel) {
1296 QEvent e(QEvent::EmbeddingControl);
1297 QApplication::sendEvent(qt.widget, &e);
1298 ::SetWindowLong(qt.widget->winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
1299 }
1300 qt.widget->setAttribute(Qt::WA_QuitOnClose, false);
1301 qt.widget->move(0, 0);
1302
1303 // initialize to sizeHint, but don't set resized flag so that container has a chance to override
1304 bool wasResized = qt.widget->testAttribute(Qt::WA_Resized);
1305 updateGeometry();
1306 if (!wasResized && qt.widget->testAttribute(Qt::WA_Resized)
1307 && qt.widget->sizePolicy() != QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)) {
1308 qt.widget->setAttribute(Qt::WA_Resized, false);
1309 }
1310 }
1311
1312 internalConnect();
1313 // install an event filter for stock events
1314 if (isWidget) {
1315 qt.object->installEventFilter(this);
1316 const QList<QWidget*> children = qFindChildren<QWidget*>(qt.object);
1317 QList<QWidget*>::ConstIterator it = children.constBegin();
1318 while (it != children.constEnd()) {
1319 (*it)->installEventFilter(this);
1320 ++it;
1321 }
1322 }
1323 return true;
1324}
1325
1326/*
1327class HackMenuData : public QMenuData
1328{
1329 friend class QAxServerBase;
1330};
1331*/
1332
1333class HackWidget : public QWidget
1334{
1335 friend class QAxServerBase;
1336};
1337/*
1338 Message handler. \a hWnd is always the ActiveX widget hosting the Qt widget.
1339 \a uMsg is handled as follows
1340 \list
1341 \i WM_CREATE The ActiveX control is created
1342 \i WM_DESTROY The QWidget is destroyed
1343 \i WM_SHOWWINDOW The QWidget is parented into the ActiveX window
1344 \i WM_PAINT The QWidget is updated
1345 \i WM_SIZE The QWidget is resized to the new size
1346 \i WM_SETFOCUS and
1347 \i WM_KILLFOCUS The client site is notified about the focus transfer
1348 \i WM_MOUSEACTIVATE The ActiveX is activated
1349 \endlist
1350
1351 The semantics of \a wParam and \a lParam depend on the value of \a uMsg.
1352*/
1353LRESULT QT_WIN_CALLBACK QAxServerBase::ActiveXProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1354{
1355 if (uMsg == WM_CREATE) {
1356 CREATESTRUCT *cs = (CREATESTRUCT*)lParam;
1357 QAxServerBase *that = (QAxServerBase*)cs->lpCreateParams;
1358
1359#ifdef GWLP_USERDATA
1360 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)that);
1361#else
1362 SetWindowLong(hWnd, GWL_USERDATA, (LONG)that);
1363#endif
1364
1365 that->m_hWnd = hWnd;
1366
1367 return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
1368 }
1369
1370 QAxServerBase *that = 0;
1371
1372#ifdef GWLP_USERDATA
1373 that = (QAxServerBase*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
1374#else
1375 that = (QAxServerBase*)GetWindowLong(hWnd, GWL_USERDATA);
1376#endif
1377
1378 if (that) {
1379 int width = that->qt.widget ? that->qt.widget->width() : 0;
1380 int height = that->qt.widget ? that->qt.widget->height() : 0;
1381 RECT rcPos = {0, 0, width + 1, height + 1};
1382
1383 switch (uMsg) {
1384 case WM_NCDESTROY:
1385 that->m_hWnd = 0;
1386 break;
1387
1388 case WM_QUERYENDSESSION:
1389 case WM_DESTROY:
1390 // save the window handle
1391 if (that->qt.widget) {
1392 that->qt.widget->hide();
1393 ::SetParent(that->qt.widget->winId(), 0);
1394 }
1395 break;
1396
1397 case WM_SHOWWINDOW:
1398 if(wParam) {
1399 that->internalCreate();
1400 if (!that->stayTopLevel) {
1401 ::SetParent(that->qt.widget->winId(), that->m_hWnd);
1402 that->qt.widget->raise();
1403 that->qt.widget->move(0, 0);
1404 }
1405 that->qt.widget->show();
1406 } else if (that->qt.widget) {
1407 that->qt.widget->hide();
1408 }
1409 break;
1410
1411 case WM_ERASEBKGND:
1412 that->updateMask();
1413 break;
1414
1415 case WM_SIZE:
1416 that->resize(QSize(LOWORD(lParam), HIWORD(lParam)));
1417 break;
1418
1419 case WM_SETFOCUS:
1420 if (that->isInPlaceActive && that->m_spClientSite && !that->inDesignMode && that->canTakeFocus) {
1421 that->DoVerb(OLEIVERB_UIACTIVATE, NULL, that->m_spClientSite, 0, that->m_hWnd, &rcPos);
1422 if (that->isUIActive) {
1423 IOleControlSite *spSite = 0;
1424 that->m_spClientSite->QueryInterface(IID_IOleControlSite, (void**)&spSite);
1425 if (spSite) {
1426 spSite->OnFocus(true);
1427 spSite->Release();
1428 }
1429 QWidget *candidate = that->qt.widget;
1430 while (!(candidate->focusPolicy() & Qt::TabFocus)) {
1431 candidate = candidate->nextInFocusChain();
1432 if (candidate == that->qt.widget) {
1433 candidate = 0;
1434 break;
1435 }
1436 }
1437 if (candidate) {
1438 candidate->setFocus();
1439 HackWidget *widget = (HackWidget*)that->qt.widget;
1440 if (::GetKeyState(VK_SHIFT) < 0)
1441 widget->focusNextPrevChild(false);
1442 }
1443 }
1444 }
1445 break;
1446
1447 case WM_KILLFOCUS:
1448 if (that->isInPlaceActive && that->isUIActive && that->m_spClientSite) {
1449 IOleControlSite *spSite = 0;
1450 that->m_spClientSite->QueryInterface(IID_IOleControlSite, (void**)&spSite);
1451 if (spSite) {
1452 if (!::IsChild(that->m_hWnd, ::GetFocus()))
1453 spSite->OnFocus(false);
1454 spSite->Release();
1455 }
1456 }
1457 break;
1458
1459 case WM_MOUSEACTIVATE:
1460 that->DoVerb(OLEIVERB_UIACTIVATE, NULL, that->m_spClientSite, 0, that->m_hWnd, &rcPos);
1461 break;
1462
1463 case WM_INITMENUPOPUP:
1464 if (that->qt.widget) {
1465 that->currentPopup = that->menuMap[(HMENU)wParam];
1466 if (!that->currentPopup)
1467 break;
1468 const QMetaObject *mo = that->currentPopup->metaObject();
1469 int index = mo->indexOfSignal("aboutToShow()");
1470 if (index < 0)
1471 break;
1472
1473 that->currentPopup->qt_metacall(QMetaObject::InvokeMetaMethod, index, 0);
1474 that->createPopup(that->currentPopup, (HMENU)wParam);
1475 return 0;
1476 }
1477 break;
1478
1479 case WM_MENUSELECT:
1480 case WM_COMMAND:
1481 if (that->qt.widget) {
1482 QMenuBar *menuBar = that->menuBar;
1483 if (!menuBar)
1484 break;
1485
1486 QObject *menuObject = 0;
1487 bool menuClosed = false;
1488
1489 if (uMsg == WM_COMMAND) {
1490 menuObject = that->actionMap.value(wParam);
1491 } else if (!lParam) {
1492 menuClosed = true;
1493 menuObject = that->currentPopup;
1494 } else {
1495 menuObject = that->actionMap.value(LOWORD(wParam));
1496 }
1497
1498 if (menuObject) {
1499 const QMetaObject *mo = menuObject->metaObject();
1500 int index = -1;
1501
1502 if (uMsg == WM_COMMAND)
1503 index = mo->indexOfSignal("activated()");
1504 else if (menuClosed)
1505 index = mo->indexOfSignal("aboutToHide()");
1506 else
1507 index = mo->indexOfSignal("hovered()");
1508
1509 if (index < 0)
1510 break;
1511
1512 menuObject->qt_metacall(QMetaObject::InvokeMetaMethod, index, 0);
1513 if (menuClosed || uMsg == WM_COMMAND)
1514 that->currentPopup = 0;
1515 return 0;
1516 }
1517 }
1518 break;
1519
1520 default:
1521 break;
1522 }
1523 }
1524
1525 return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
1526}
1527
1528/*!
1529 Creates the window hosting the QWidget.
1530*/
1531HWND QAxServerBase::create(HWND hWndParent, RECT& rcPos)
1532{
1533 Q_ASSERT(isWidget && qt.widget);
1534
1535 static ATOM atom = 0;
1536 HINSTANCE hInst = (HINSTANCE)qAxInstance;
1537 EnterCriticalSection(&createWindowSection);
1538 QString cn(QLatin1String("QAxControl"));
1539 cn += QString::number((quintptr)ActiveXProc);
1540 if (!atom) {
1541 WNDCLASS wcTemp;
1542 wcTemp.style = CS_DBLCLKS;
1543 wcTemp.cbClsExtra = 0;
1544 wcTemp.cbWndExtra = 0;
1545 wcTemp.hbrBackground = 0;
1546 wcTemp.hCursor = 0;
1547 wcTemp.hIcon = 0;
1548 wcTemp.hInstance = hInst;
1549 wcTemp.lpszClassName = (wchar_t*)cn.utf16();
1550 wcTemp.lpszMenuName = 0;
1551 wcTemp.lpfnWndProc = ActiveXProc;
1552
1553 atom = RegisterClass(&wcTemp);
1554 }
1555 LeaveCriticalSection(&createWindowSection);
1556 if (!atom && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
1557 return 0;
1558
1559 Q_ASSERT(!m_hWnd);
1560 HWND hWnd = ::CreateWindow((wchar_t*)cn.utf16(), 0,
1561 WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
1562 rcPos.left, rcPos.top, rcPos.right - rcPos.left,
1563 rcPos.bottom - rcPos.top, hWndParent, 0, hInst, this);
1564
1565 Q_ASSERT(m_hWnd == hWnd);
1566
1567 updateMask();
1568 EnableWindow(m_hWnd, qt.widget->isEnabled());
1569
1570 return hWnd;
1571}
1572
1573/*
1574 Recoursively creates Win32 submenus.
1575*/
1576HMENU QAxServerBase::createPopup(QMenu *popup, HMENU oldMenu)
1577{
1578 HMENU popupMenu = oldMenu ? oldMenu : CreatePopupMenu();
1579 menuMap.insert(popupMenu, popup);
1580
1581 if (oldMenu) while (GetMenuItemCount(oldMenu)) {
1582 DeleteMenu(oldMenu, 0, MF_BYPOSITION);
1583 }
1584
1585 const QList<QAction*> actions = popup->actions();
1586 for (int i = 0; i < actions.count(); ++i) {
1587 QAction *action = actions.at(i);
1588
1589 uint flags = action->isEnabled() ? MF_ENABLED : MF_GRAYED;
1590 if (action->isSeparator())
1591 flags |= MF_SEPARATOR;
1592 else if (action->menu())
1593 flags |= MF_POPUP;
1594 else
1595 flags |= MF_STRING;
1596 if (action->isChecked())
1597 flags |= MF_CHECKED;
1598
1599 ushort itemId;
1600 if (flags & MF_POPUP) {
1601 itemId = static_cast<ushort>(
1602 reinterpret_cast<quintptr>(createPopup(action->menu()))
1603 );
1604 } else {
1605 itemId = static_cast<ushort>(reinterpret_cast<quintptr>(action));
1606 actionMap.remove(itemId);
1607 actionMap.insert(itemId, action);
1608 }
1609 AppendMenu(popupMenu, flags, itemId, (const wchar_t *)action->text().utf16());
1610 }
1611 if (oldMenu)
1612 DrawMenuBar(hwndMenuOwner);
1613 return popupMenu;
1614}
1615
1616/*!
1617 Creates a Win32 menubar.
1618*/
1619void QAxServerBase::createMenu(QMenuBar *menuBar)
1620{
1621 hmenuShared = ::CreateMenu();
1622
1623 int edit = 0;
1624 int object = 0;
1625 int help = 0;
1626
1627 const QList<QAction*> actions = menuBar->actions();
1628 for (int i = 0; i < actions.count(); ++i) {
1629 QAction *action = actions.at(i);
1630
1631 uint flags = action->isEnabled() ? MF_ENABLED : MF_GRAYED;
1632 if (action->isSeparator())
1633 flags |= MF_SEPARATOR;
1634 else if (action->menu())
1635 flags |= MF_POPUP;
1636 else
1637 flags |= MF_STRING;
1638
1639 if (action->text() == QCoreApplication::translate(qt.widget->metaObject()->className(), "&Edit"))
1640 edit++;
1641 else if (action->text() == QCoreApplication::translate(qt.widget->metaObject()->className(), "&Help"))
1642 help++;
1643 else
1644 object++;
1645
1646 ushort itemId;
1647 if (flags & MF_POPUP) {
1648 itemId = static_cast<ushort>(
1649 reinterpret_cast<quintptr>(createPopup(action->menu()))
1650 );
1651 } else {
1652 itemId = static_cast<ushort>(reinterpret_cast<quintptr>(action));
1653 actionMap.insert(itemId, action);
1654 }
1655 AppendMenu(hmenuShared, flags, itemId, (const wchar_t *)action->text().utf16());
1656 }
1657
1658 OLEMENUGROUPWIDTHS menuWidths = {0,edit,0,object,0,help};
1659 HRESULT hres = m_spInPlaceFrame->InsertMenus(hmenuShared, &menuWidths);
1660 if (FAILED(hres)) {
1661 ::DestroyMenu(hmenuShared);
1662 hmenuShared = 0;
1663 return;
1664 }
1665
1666 m_spInPlaceFrame->GetWindow(&hwndMenuOwner);
1667
1668 holemenu = OleCreateMenuDescriptor(hmenuShared, &menuWidths);
1669 hres = m_spInPlaceFrame->SetMenu(hmenuShared, holemenu, m_hWnd);
1670 if (FAILED(hres)) {
1671 ::DestroyMenu(hmenuShared);
1672 hmenuShared = 0;
1673 OleDestroyMenuDescriptor(holemenu);
1674 }
1675}
1676
1677/*!
1678 Remove the Win32 menubar.
1679*/
1680void QAxServerBase::removeMenu()
1681{
1682 if (hmenuShared)
1683 m_spInPlaceFrame->RemoveMenus(hmenuShared);
1684 holemenu = 0;
1685 m_spInPlaceFrame->SetMenu(0, 0, m_hWnd);
1686 if (hmenuShared) {
1687 DestroyMenu(hmenuShared);
1688 hmenuShared = 0;
1689 menuMap.clear();
1690 }
1691 hwndMenuOwner = 0;
1692}
1693
1694extern bool ignoreSlots(const char *test);
1695extern bool ignoreProps(const char *test);
1696
1697/*!
1698 Makes sure the type info is loaded
1699*/
1700void QAxServerBase::ensureMetaData()
1701{
1702 if (!m_spTypeInfo) {
1703 qAxTypeLibrary->GetTypeInfoOfGuid(qAxFactory()->interfaceID(class_name), &m_spTypeInfo);
1704 m_spTypeInfo->AddRef();
1705 }
1706}
1707
1708/*!
1709 \internal
1710 Returns true if the property \a index is exposed to COM and should
1711 be saved/loaded.
1712*/
1713bool QAxServerBase::isPropertyExposed(int index)
1714{
1715 if (!theObject)
1716 return false;
1717
1718 bool result = false;
1719 const QMetaObject *mo = theObject->metaObject();
1720
1721 int qtProps = 0;
1722 if (theObject->isWidgetType())
1723 qtProps = QWidget::staticMetaObject.propertyCount();
1724 QMetaProperty property = mo->property(index);
1725 if (index <= qtProps && ignoreProps(property.name()))
1726 return result;
1727
1728 BSTR bstrNames = QStringToBSTR(QLatin1String(property.name()));
1729 DISPID dispId;
1730 GetIDsOfNames(IID_NULL, (BSTR*)&bstrNames, 1, LOCALE_USER_DEFAULT, &dispId);
1731 result = dispId != DISPID_UNKNOWN;
1732 SysFreeString(bstrNames);
1733
1734 return result;
1735}
1736
1737
1738/*!
1739 \internal
1740 Updates the view, or asks the client site to do so.
1741*/
1742void QAxServerBase::update()
1743{
1744 if (isInPlaceActive) {
1745 if (m_hWnd)
1746 ::InvalidateRect(m_hWnd, 0, true);
1747 else if (m_spInPlaceSite)
1748 m_spInPlaceSite->InvalidateRect(NULL, true);
1749 } else if (m_spAdviseSink) {
1750 m_spAdviseSink->OnViewChange(DVASPECT_CONTENT, -1);
1751 for (int i = 0; i < adviseSinks.count(); ++i) {
1752 adviseSinks.at(i).pAdvSink->OnViewChange(DVASPECT_CONTENT, -1);
1753 }
1754 }
1755}
1756
1757/*!
1758 Resizes the control, faking a QResizeEvent if required
1759*/
1760void QAxServerBase::resize(const QSize &size)
1761{
1762 if (!isWidget || !qt.widget || !size.isValid() || size == QSize(0, 0))
1763 return;
1764
1765 QSize oldSize = qt.widget->size();
1766 qt.widget->resize(size);
1767 QSize newSize = qt.widget->size();
1768 // make sure we get a resize event even if not embedded as a control
1769 if (!m_hWnd && !qt.widget->isVisible() && newSize != oldSize) {
1770 QResizeEvent resizeEvent(newSize, oldSize);
1771#ifndef QT_DLL // import from static library
1772 extern bool qt_sendSpontaneousEvent(QObject*,QEvent*);
1773#endif
1774 qt_sendSpontaneousEvent(qt.widget, &resizeEvent);
1775 }
1776 m_currentExtent = qt.widget->size();
1777}
1778
1779/*!
1780 \internal
1781
1782 Updates the internal size values.
1783*/
1784void QAxServerBase::updateGeometry()
1785{
1786 if (!isWidget || !qt.widget)
1787 return;
1788
1789 const QSize sizeHint = qt.widget->sizeHint();
1790 const QSize size = qt.widget->size();
1791 if (sizeHint.isValid()) { // if provided, adjust to sizeHint
1792 QSize newSize = size;
1793 if (!qt.widget->testAttribute(Qt::WA_Resized)) {
1794 newSize = sizeHint;
1795 } else { // according to sizePolicy rules if already resized
1796 QSizePolicy sizePolicy = qt.widget->sizePolicy();
1797 if (sizeHint.width() > size.width() && !(sizePolicy.horizontalPolicy() & QSizePolicy::ShrinkFlag))
1798 newSize.setWidth(sizeHint.width());
1799 if (sizeHint.width() < size.width() && !(sizePolicy.horizontalPolicy() & QSizePolicy::GrowFlag))
1800 newSize.setWidth(sizeHint.width());
1801 if (sizeHint.height() > size.height() && !(sizePolicy.verticalPolicy() & QSizePolicy::ShrinkFlag))
1802 newSize.setHeight(sizeHint.height());
1803 if (sizeHint.height() < size.height() && !(sizePolicy.verticalPolicy() & QSizePolicy::GrowFlag))
1804 newSize.setHeight(sizeHint.height());
1805 }
1806 resize(newSize);
1807
1808 // set an initial size suitable for embedded controls
1809 } else if (!qt.widget->testAttribute(Qt::WA_Resized)) {
1810 resize(QSize(100, 100));
1811 qt.widget->setAttribute(Qt::WA_Resized, false);
1812 }
1813}
1814
1815/*!
1816 \internal
1817
1818 Updates the mask of the widget parent.
1819*/
1820void QAxServerBase::updateMask()
1821{
1822 if (!isWidget || !qt.widget || qt.widget->mask().isEmpty())
1823 return;
1824
1825 QRegion rgn = qt.widget->mask();
1826 HRGN hrgn = rgn.handle();
1827
1828 // Since SetWindowRegion takes ownership
1829 HRGN wr = CreateRectRgn(0,0,0,0);
1830 CombineRgn(wr, hrgn, 0, RGN_COPY);
1831 SetWindowRgn(m_hWnd, wr, true);
1832}
1833
1834static bool checkHRESULT(HRESULT hres)
1835{
1836 const char *name = 0;
1837 switch(hres) {
1838 case S_OK:
1839 return true;
1840 case DISP_E_BADPARAMCOUNT:
1841#if defined(QT_CHECK_STATE)
1842 qWarning("QAxBase: Error calling IDispatch member %s: Bad parameter count", name);
1843#endif
1844 return false;
1845 case DISP_E_BADVARTYPE:
1846#if defined(QT_CHECK_STATE)
1847 qWarning("QAxBase: Error calling IDispatch member %s: Bad variant type", name);
1848#endif
1849 return false;
1850 case DISP_E_EXCEPTION:
1851#if defined(QT_CHECK_STATE)
1852 qWarning("QAxBase: Error calling IDispatch member %s: Exception thrown by server", name);
1853#endif
1854 return false;
1855 case DISP_E_MEMBERNOTFOUND:
1856#if defined(QT_CHECK_STATE)
1857 qWarning("QAxBase: Error calling IDispatch member %s: Member not found", name);
1858#endif
1859 return false;
1860 case DISP_E_NONAMEDARGS:
1861#if defined(QT_CHECK_STATE)
1862 qWarning("QAxBase: Error calling IDispatch member %s: No named arguments", name);
1863#endif
1864 return false;
1865 case DISP_E_OVERFLOW:
1866#if defined(QT_CHECK_STATE)
1867 qWarning("QAxBase: Error calling IDispatch member %s: Overflow", name);
1868#endif
1869 return false;
1870 case DISP_E_PARAMNOTFOUND:
1871#if defined(QT_CHECK_STATE)
1872 qWarning("QAxBase: Error calling IDispatch member %s: Parameter not found", name);
1873#endif
1874 return false;
1875 case DISP_E_TYPEMISMATCH:
1876#if defined(QT_CHECK_STATE)
1877 qWarning("QAxBase: Error calling IDispatch member %s: Type mismatch", name);
1878#endif
1879 return false;
1880 case DISP_E_UNKNOWNINTERFACE:
1881#if defined(QT_CHECK_STATE)
1882 qWarning("QAxBase: Error calling IDispatch member %s: Unknown interface", name);
1883#endif
1884 return false;
1885 case DISP_E_UNKNOWNLCID:
1886#if defined(QT_CHECK_STATE)
1887 qWarning("QAxBase: Error calling IDispatch member %s: Unknown locale ID", name);
1888#endif
1889 return false;
1890 case DISP_E_PARAMNOTOPTIONAL:
1891#if defined(QT_CHECK_STATE)
1892 qWarning("QAxBase: Error calling IDispatch member %s: Non-optional parameter missing", name);
1893#endif
1894 return false;
1895 default:
1896#if defined(QT_CHECK_STATE)
1897 qWarning("QAxBase: Error calling IDispatch member %s: Unknown error", name);
1898#endif
1899 return false;
1900 }
1901}
1902
1903static inline QByteArray paramType(const QByteArray &ptype, bool *out)
1904{
1905 *out = ptype.endsWith('&') || ptype.endsWith("**");
1906 if (*out) {
1907 QByteArray res(ptype);
1908 res.truncate(res.length() - 1);
1909 return res;
1910 }
1911
1912 return ptype;
1913}
1914
1915/*!
1916 Catches all signals emitted by the Qt widget and fires the respective COM event.
1917
1918 \a isignal is the Qt Meta Object index of the received signal, and \a _o the
1919 signal parameters.
1920*/
1921int QAxServerBase::qt_metacall(QMetaObject::Call call, int index, void **argv)
1922{
1923 Q_ASSERT(call == QMetaObject::InvokeMetaMethod);
1924
1925 if (index == -1) {
1926 if (sender() && m_spInPlaceFrame) {
1927 if (qobject_cast<QStatusBar*>(sender()) != statusBar)
1928 return true;
1929
1930 if (statusBar->isHidden()) {
1931 QString message = *(QString*)argv[1];
1932 m_spInPlaceFrame->SetStatusText(QStringToBSTR(message));
1933 }
1934 }
1935 return true;
1936 }
1937
1938 if (freezeEvents || inDesignMode)
1939 return true;
1940
1941 ensureMetaData();
1942
1943 // get the signal information.
1944 const QMetaObject *mo = qt.object->metaObject();
1945 QMetaMethod signal;
1946 DISPID eventId = index;
1947 int pcount = 0;
1948 QByteArray type;
1949 QList<QByteArray> ptypes;
1950
1951 switch(index) {
1952 case DISPID_KEYDOWN:
1953 case DISPID_KEYUP:
1954 pcount = 2;
1955 ptypes << "int&" << "int";
1956 break;
1957 case DISPID_KEYPRESS:
1958 pcount = 1;
1959 ptypes << "int&";
1960 break;
1961 case DISPID_MOUSEDOWN:
1962 case DISPID_MOUSEMOVE:
1963 case DISPID_MOUSEUP:
1964 pcount = 4;
1965 ptypes << "int" << "int" << "int" << "int";
1966 break;
1967 case DISPID_CLICK:
1968 pcount = 0;
1969 break;
1970 case DISPID_DBLCLICK:
1971 pcount = 0;
1972 break;
1973 default:
1974 {
1975 signal = mo->method(index);
1976 Q_ASSERT(signal.methodType() == QMetaMethod::Signal);
1977 type = signal.typeName();
1978 QByteArray signature(signal.signature());
1979 QByteArray name(signature);
1980 name.truncate(name.indexOf('('));
1981
1982 eventId = signalCache.value(index, -1);
1983 if (eventId == -1) {
1984 ITypeInfo *eventInfo = 0;
1985 qAxTypeLibrary->GetTypeInfoOfGuid(qAxFactory()->eventsID(class_name), &eventInfo);
1986 if (eventInfo) {
1987 QString uni_name = QLatin1String(name);
1988 const OLECHAR *olename = reinterpret_cast<const OLECHAR *>(uni_name.utf16());
1989 eventInfo->GetIDsOfNames((OLECHAR**)&olename, 1, &eventId);
1990 eventInfo->Release();
1991 }
1992 }
1993
1994 signature = signature.mid(name.length() + 1);
1995 signature.truncate(signature.length() - 1);
1996
1997 if (!signature.isEmpty())
1998 ptypes = signature.split(',');
1999
2000 pcount = ptypes.count();
2001 }
2002 break;
2003 }
2004 if (pcount && !argv) {
2005 qWarning("QAxServerBase::qt_metacall: Missing %d arguments", pcount);
2006 return false;
2007 }
2008 if (eventId == -1)
2009 return false;
2010
2011 // For all connected event sinks...
2012 IConnectionPoint *cpoint = 0;
2013 GUID IID_QAxEvents = qAxFactory()->eventsID(class_name);
2014 FindConnectionPoint(IID_QAxEvents, &cpoint);
2015 if (cpoint) {
2016 IEnumConnections *clist = 0;
2017 cpoint->EnumConnections(&clist);
2018 if (clist) {
2019 clist->Reset();
2020 ULONG cc = 1;
2021 CONNECTDATA c[1];
2022 clist->Next(cc, (CONNECTDATA*)&c, &cc);
2023 if (cc) {
2024 // setup parameters
2025 unsigned int argErr = 0;
2026 DISPPARAMS dispParams;
2027 dispParams.cArgs = pcount;
2028 dispParams.cNamedArgs = 0;
2029 dispParams.rgdispidNamedArgs = 0;
2030 dispParams.rgvarg = 0;
2031
2032 if (pcount) // Use malloc/free for eval package compatibility
2033 dispParams.rgvarg = (VARIANTARG*)malloc(pcount * sizeof(VARIANTARG));
2034 int p = 0;
2035 for (p = 0; p < pcount; ++p) {
2036 VARIANT *arg = dispParams.rgvarg + (pcount - p - 1);
2037 VariantInit(arg);
2038
2039 bool out;
2040 QByteArray ptype = paramType(ptypes.at(p), &out);
2041 QVariant variant;
2042 if (mo->indexOfEnumerator(ptype) != -1) {
2043 // convert enum values to int
2044 variant = QVariant(*reinterpret_cast<int *>(argv[p+1]));
2045 } else {
2046 QVariant::Type vt = QVariant::nameToType(ptype);
2047 if (vt == QVariant::UserType) {
2048 if (ptype.endsWith('*')) {
2049 variant = QVariant(QMetaType::type(ptype), (void**)argv[p+1]);
2050 // qVariantSetValue(variant, *(void**)(argv[p + 1]), ptype);
2051 } else {
2052 variant = QVariant(QMetaType::type(ptype), argv[p+1]);
2053 // qVariantSetValue(variant, argv[p + 1], ptype);
2054 }
2055 } else {
2056 variant = QVariant(vt, argv[p + 1]);
2057 }
2058 }
2059
2060 QVariantToVARIANT(variant, *arg, type, out);
2061 }
2062
2063 VARIANT retval;
2064 VariantInit(&retval);
2065 VARIANT *pretval = 0;
2066 if (!type.isEmpty())
2067 pretval = &retval;
2068
2069 // call listeners (through IDispatch)
2070 while (cc) {
2071 if (c->pUnk) {
2072 IDispatch *disp = 0;
2073 c->pUnk->QueryInterface(IID_QAxEvents, (void**)&disp);
2074 if (disp) {
2075 disp->Invoke(eventId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispParams, pretval, 0, &argErr);
2076
2077 // update out-parameters and return value
2078 if (index > 0) {
2079 for (p = 0; p < pcount; ++p) {
2080 bool out;
2081 QByteArray ptype = paramType(ptypes.at(p), &out);
2082 if (out)
2083 QVariantToVoidStar(VARIANTToQVariant(dispParams.rgvarg[pcount - p - 1], ptype), argv[p+1], ptype);
2084 }
2085 if (pretval)
2086 QVariantToVoidStar(VARIANTToQVariant(retval, type), argv[0], type);
2087 }
2088 disp->Release();
2089 }
2090 c->pUnk->Release(); // AddRef'ed by clist->Next implementation
2091 }
2092 clist->Next(cc, (CONNECTDATA*)&c, &cc);
2093 }
2094
2095 // clean up
2096 for (p = 0; p < pcount; ++p)
2097 clearVARIANT(dispParams.rgvarg+p);
2098 free(dispParams.rgvarg);
2099 }
2100 clist->Release();
2101 }
2102 cpoint->Release();
2103 }
2104
2105 return true;
2106}
2107
2108/*!
2109 Call IPropertyNotifySink of connected clients.
2110 \a dispId specifies the ID of the property that changed.
2111*/
2112bool QAxServerBase::emitRequestPropertyChange(const char *property)
2113{
2114 long dispId = -1;
2115
2116 IConnectionPoint *cpoint = 0;
2117 FindConnectionPoint(IID_IPropertyNotifySink, &cpoint);
2118 if (cpoint) {
2119 IEnumConnections *clist = 0;
2120 cpoint->EnumConnections(&clist);
2121 if (clist) {
2122 clist->Reset();
2123 ULONG cc = 1;
2124 CONNECTDATA c[1];
2125 clist->Next(cc, (CONNECTDATA*)&c, &cc);
2126 if (cc) {
2127 if (dispId == -1) {
2128 BSTR bstr = QStringToBSTR(QLatin1String(property));
2129 GetIDsOfNames(IID_NULL, &bstr, 1, LOCALE_USER_DEFAULT, &dispId);
2130 SysFreeString(bstr);
2131 }
2132 if (dispId != -1) while (cc) {
2133 if (c->pUnk) {
2134 IPropertyNotifySink *sink = 0;
2135 c->pUnk->QueryInterface(IID_IPropertyNotifySink, (void**)&sink);
2136 bool disallows = sink && sink->OnRequestEdit(dispId) == S_FALSE;
2137 sink->Release();
2138 c->pUnk->Release();
2139 if (disallows) { // a client disallows the property to change
2140 clist->Release();
2141 cpoint->Release();
2142 return false;
2143 }
2144 }
2145 clist->Next(cc, (CONNECTDATA*)&c, &cc);
2146 }
2147 }
2148 clist->Release();
2149 }
2150 cpoint->Release();
2151 }
2152 dirtyflag = true;
2153 return true;
2154}
2155
2156/*!
2157 Call IPropertyNotifySink of connected clients.
2158 \a dispId specifies the ID of the property that changed.
2159*/
2160void QAxServerBase::emitPropertyChanged(const char *property)
2161{
2162 long dispId = -1;
2163
2164 IConnectionPoint *cpoint = 0;
2165 FindConnectionPoint(IID_IPropertyNotifySink, &cpoint);
2166 if (cpoint) {
2167 IEnumConnections *clist = 0;
2168 cpoint->EnumConnections(&clist);
2169 if (clist) {
2170 clist->Reset();
2171 ULONG cc = 1;
2172 CONNECTDATA c[1];
2173 clist->Next(cc, (CONNECTDATA*)&c, &cc);
2174 if (cc) {
2175 if (dispId == -1) {
2176 BSTR bstr = QStringToBSTR(QLatin1String(property));
2177 GetIDsOfNames(IID_NULL, &bstr, 1, LOCALE_USER_DEFAULT, &dispId);
2178 SysFreeString(bstr);
2179 }
2180 if (dispId != -1) while (cc) {
2181 if (c->pUnk) {
2182 IPropertyNotifySink *sink = 0;
2183 c->pUnk->QueryInterface(IID_IPropertyNotifySink, (void**)&sink);
2184 if (sink) {
2185 sink->OnChanged(dispId);
2186 sink->Release();
2187 }
2188 c->pUnk->Release();
2189 }
2190 clist->Next(cc, (CONNECTDATA*)&c, &cc);
2191 }
2192 }
2193 clist->Release();
2194 }
2195 cpoint->Release();
2196 }
2197 dirtyflag = true;
2198}
2199
2200//**** IProvideClassInfo
2201/*
2202 Provide the ITypeInfo implementation for the COM class.
2203*/
2204HRESULT WINAPI QAxServerBase::GetClassInfo(ITypeInfo** pptinfo)
2205{
2206 if (!pptinfo)
2207 return E_POINTER;
2208
2209 *pptinfo = 0;
2210 if (!qAxTypeLibrary)
2211 return DISP_E_BADINDEX;
2212
2213 return qAxTypeLibrary->GetTypeInfoOfGuid(qAxFactory()->classID(class_name), pptinfo);
2214}
2215
2216//**** IProvideClassInfo2
2217/*
2218 Provide the ID of the event interface.
2219*/
2220HRESULT WINAPI QAxServerBase::GetGUID(DWORD dwGuidKind, GUID* pGUID)
2221{
2222 if (!pGUID)
2223 return E_POINTER;
2224
2225 if (dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID) {
2226 *pGUID = qAxFactory()->eventsID(class_name);
2227 return S_OK;
2228 }
2229 *pGUID = GUID_NULL;
2230 return E_FAIL;
2231}
2232
2233//**** IDispatch
2234/*
2235 Returns the number of class infos for this IDispatch.
2236*/
2237HRESULT WINAPI QAxServerBase::GetTypeInfoCount(UINT* pctinfo)
2238{
2239 if (!pctinfo)
2240 return E_POINTER;
2241
2242 *pctinfo = qAxTypeLibrary ? 1 : 0;
2243 return S_OK;
2244}
2245
2246/*
2247 Provides the ITypeInfo for this IDispatch implementation.
2248*/
2249HRESULT WINAPI QAxServerBase::GetTypeInfo(UINT itinfo, LCID /*lcid*/, ITypeInfo** pptinfo)
2250{
2251 if (!pptinfo)
2252 return E_POINTER;
2253
2254 if (!qAxTypeLibrary)
2255 return DISP_E_BADINDEX;
2256
2257 ensureMetaData();
2258
2259 *pptinfo = m_spTypeInfo;
2260 (*pptinfo)->AddRef();
2261
2262 return S_OK;
2263}
2264
2265/*
2266 Provides the names of the methods implemented in this IDispatch implementation.
2267*/
2268HRESULT WINAPI QAxServerBase::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
2269 LCID /*lcid*/, DISPID* rgdispid)
2270{
2271 if (!rgszNames || !rgdispid)
2272 return E_POINTER;
2273
2274 if (!qAxTypeLibrary)
2275 return DISP_E_UNKNOWNNAME;
2276
2277 ensureMetaData();
2278 if (!m_spTypeInfo)
2279 return DISP_E_UNKNOWNNAME;
2280
2281 return m_spTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
2282}
2283
2284/*
2285 Map the COM call to the Qt slot/property for \a dispidMember.
2286*/
2287HRESULT WINAPI QAxServerBase::Invoke(DISPID dispidMember, REFIID riid,
2288 LCID /*lcid*/, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pvarResult,
2289 EXCEPINFO* pexcepinfo, UINT* puArgErr)
2290{
2291 if (riid != IID_NULL)
2292 return DISP_E_UNKNOWNINTERFACE;
2293 if (!theObject)
2294 return E_UNEXPECTED;
2295
2296 HRESULT res = DISP_E_MEMBERNOTFOUND;
2297
2298 bool uniqueIndex = wFlags == DISPATCH_PROPERTYGET || wFlags == DISPATCH_PROPERTYPUT || wFlags == DISPATCH_METHOD;
2299
2300 int index = uniqueIndex ? indexCache.value(dispidMember, -1) : -1;
2301 QByteArray name;
2302 if (index == -1) {
2303 ensureMetaData();
2304
2305 // This property or method is invoked when an ActiveX client specifies
2306 // the object name without a property or method. We only support property.
2307 if (dispidMember == DISPID_VALUE && (wFlags == DISPATCH_PROPERTYGET || wFlags == DISPATCH_PROPERTYPUT)) {
2308 const QMetaObject *mo = qt.object->metaObject();
2309 index = mo->indexOfClassInfo("DefaultProperty");
2310 if (index != -1) {
2311 name = mo->classInfo(index).value();
2312 index = mo->indexOfProperty(name);
2313 }
2314 } else {
2315 BSTR bname;
2316 UINT cname = 0;
2317 if (m_spTypeInfo)
2318 m_spTypeInfo->GetNames(dispidMember, &bname, 1, &cname);
2319 if (!cname)
2320 return res;
2321
2322 name = QString::fromWCharArray(bname).toLatin1();
2323 SysFreeString(bname);
2324 }
2325 }
2326
2327 const QMetaObject *mo = qt.object->metaObject();
2328 QSize oldSizeHint;
2329 if (isWidget)
2330 oldSizeHint = qt.widget->sizeHint();
2331
2332 switch (wFlags) {
2333 case DISPATCH_PROPERTYGET|DISPATCH_METHOD:
2334 case DISPATCH_PROPERTYGET:
2335 {
2336 if (index == -1) {
2337 index = mo->indexOfProperty(name);
2338 if (index == -1 && wFlags == DISPATCH_PROPERTYGET)
2339 return res;
2340 }
2341
2342 QMetaProperty property;
2343 if (index < mo->propertyCount())
2344 property = mo->property(index);
2345
2346 if (property.isReadable()) {
2347 if (!pvarResult)
2348 return DISP_E_PARAMNOTOPTIONAL;
2349 if (pDispParams->cArgs ||
2350 pDispParams->cNamedArgs)
2351 return DISP_E_BADPARAMCOUNT;
2352
2353 QVariant var = qt.object->property(property.name());
2354 if (!var.isValid())
2355 res = DISP_E_MEMBERNOTFOUND;
2356 else if (!QVariantToVARIANT(var, *pvarResult))
2357 res = DISP_E_TYPEMISMATCH;
2358 else
2359 res = S_OK;
2360 break;
2361 } else if (wFlags == DISPATCH_PROPERTYGET) {
2362 break;
2363 }
2364 }
2365 // FALLTHROUGH if wFlags == DISPATCH_PROPERTYGET|DISPATCH_METHOD AND not a property.
2366 case DISPATCH_METHOD:
2367 {
2368 int nameLength = 0;
2369 if (index == -1) {
2370 nameLength = name.length();
2371 name += '(';
2372 // no parameter - shortcut
2373 if (!pDispParams->cArgs)
2374 index = mo->indexOfSlot((name + ')'));
2375 // search
2376 if (index == -1) {
2377 for (int i = 0; i < mo->methodCount(); ++i) {
2378 const QMetaMethod slot(mo->method(i));
2379 if (slot.methodType() == QMetaMethod::Slot && QByteArray(slot.signature()).startsWith(name)) {
2380 index = i;
2381 break;
2382 }
2383 }
2384 // resolve overloads
2385 if (index == -1) {
2386 QRegExp regexp(QLatin1String("_([0-9])\\("));
2387 if (regexp.lastIndexIn(QString::fromLatin1(name.constData())) != -1) {
2388 name = name.left(name.length() - regexp.cap(0).length()) + '(';
2389 int overload = regexp.cap(1).toInt() + 1;
2390
2391 for (int s = 0; s < qt.object->metaObject()->methodCount(); ++s) {
2392 QMetaMethod slot = qt.object->metaObject()->method(s);
2393 if (slot.methodType() == QMetaMethod::Slot && QByteArray(slot.signature()).startsWith(name)) {
2394 if (!--overload) {
2395 index = s;
2396 break;
2397 }
2398 }
2399 }
2400 }
2401 }
2402 if (index == -1)
2403 return res;
2404 }
2405 }
2406
2407 int lookupIndex = index;
2408
2409 // get slot info
2410 QMetaMethod slot(mo->method(index));
2411 Q_ASSERT(slot.methodType() == QMetaMethod::Slot);
2412 QByteArray type = slot.typeName();
2413 name = slot.signature();
2414 nameLength = name.indexOf('(');
2415 QByteArray prototype = name.mid(nameLength + 1);
2416 prototype.truncate(prototype.length() - 1);
2417 QList<QByteArray> ptypes;
2418 if (!prototype.isEmpty())
2419 ptypes = prototype.split(',');
2420 int pcount = ptypes.count();
2421
2422 // verify parameter count
2423 if (pcount > pDispParams->cArgs) {
2424 // count cloned slots immediately following the real thing
2425 int defArgs = 0;
2426 while (index < mo->methodCount()) {
2427 ++index;
2428 slot = mo->method(index);
2429 if (!(slot.attributes() & QMetaMethod::Cloned))
2430 break;
2431 --pcount;
2432 // found a matching overload. ptypes still valid
2433 if (pcount <= pDispParams->cArgs)
2434 break;
2435 }
2436 // still wrong :(
2437 if (pcount > pDispParams->cArgs)
2438 return DISP_E_PARAMNOTOPTIONAL;
2439 } else if (pcount < pDispParams->cArgs) {
2440 return DISP_E_BADPARAMCOUNT;
2441 }
2442
2443 // setup parameters (pcount + return)
2444 bool ok = true;
2445 void *static_argv[QAX_NUM_PARAMS + 1];
2446 QVariant static_varp[QAX_NUM_PARAMS + 1];
2447 void *static_argv_pointer[QAX_NUM_PARAMS + 1];
2448
2449 int totalParam = pcount;
2450 if (!type.isEmpty())
2451 ++totalParam;
2452
2453 void **argv = 0; // the actual array passed into qt_metacall
2454 void **argv_pointer = 0; // in case we need an additional level of indirection
2455 QVariant *varp = 0; // QVariants to hold the temporary Qt data object for us
2456
2457 if (totalParam) {
2458 if (totalParam <= QAX_NUM_PARAMS) {
2459 argv = static_argv;
2460 argv_pointer = static_argv_pointer;
2461 varp = static_varp;
2462 } else {
2463 argv = new void*[pcount + 1];
2464 argv_pointer = new void*[pcount + 1];
2465 varp = new QVariant[pcount + 1];
2466 }
2467
2468 argv_pointer[0] = 0;
2469 }
2470
2471 for (int p = 0; p < pcount; ++p) {
2472 // map the VARIANT to the void*
2473 bool out;
2474 QByteArray ptype = paramType(ptypes.at(p), &out);
2475 varp[p + 1] = VARIANTToQVariant(pDispParams->rgvarg[pcount - p - 1], ptype);
2476 argv_pointer[p + 1] = 0;
2477 if (varp[p + 1].isValid()) {
2478 if (varp[p + 1].type() == QVariant::UserType) {
2479 argv[p + 1] = varp[p + 1].data();
2480 } else if (ptype == "QVariant") {
2481 argv[p + 1] = varp + p + 1;
2482 } else {
2483 argv[p + 1] = const_cast<void*>(varp[p + 1].constData());
2484 if (ptype.endsWith('*')) {
2485 argv_pointer[p + 1] = argv[p + 1];
2486 argv[p + 1] = argv_pointer + p + 1;
2487 }
2488 }
2489 } else if (ptype == "QVariant") {
2490 argv[p + 1] = varp + p + 1;
2491 } else {
2492 if (puArgErr)
2493 *puArgErr = pcount-p-1;
2494 ok = false;
2495 }
2496 }
2497
2498 // return value
2499 if (!type.isEmpty()) {
2500 QVariant::Type vt = QVariant::nameToType(type);
2501 if (vt == QVariant::UserType)
2502 vt = QVariant::Invalid;
2503 varp[0] = QVariant(vt);
2504 if (varp[0].type() == QVariant::Invalid && mo->indexOfEnumerator(slot.typeName()) != -1)
2505 varp[0] = QVariant(QVariant::Int);
2506
2507 if (varp[0].type() == QVariant::Invalid) {
2508 if (type == "QVariant")
2509 argv[0] = varp;
2510 else
2511 argv[0] = 0;
2512 } else {
2513 argv[0] = const_cast<void*>(varp[0].constData());
2514 }
2515 if (type.endsWith('*')) {
2516 argv_pointer[0] = argv[0];
2517 argv[0] = argv_pointer;
2518 }
2519 }
2520
2521 // call the slot if everthing went fine.
2522 if (ok) {
2523 ++invokeCount;
2524 qt.object->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
2525 if (--invokeCount < 0)
2526 invokeCount = 0;
2527
2528 // update reference parameters and return value
2529 for (int p = 0; p < pcount; ++p) {
2530 bool out;
2531 QByteArray ptype = paramType(ptypes.at(p), &out);
2532 if (out) {
2533 if (!QVariantToVARIANT(varp[p + 1], pDispParams->rgvarg[pcount - p - 1], ptype, out))
2534 ok = false;
2535 }
2536 }
2537 if (!type.isEmpty() && pvarResult) {
2538 if (!varp[0].isValid() && type != "QVariant")
2539 varp[0] = QVariant(QMetaType::type(type), argv_pointer);
2540// qVariantSetValue(varp[0], argv_pointer[0], type);
2541 ok = QVariantToVARIANT(varp[0], *pvarResult, type);
2542 }
2543 }
2544 if (argv && argv != static_argv) {
2545 delete []argv;
2546 delete []argv_pointer;
2547 delete []varp;
2548 }
2549
2550 res = ok ? S_OK : DISP_E_TYPEMISMATCH;
2551
2552 // reset in case index changed for default-arg handling
2553 index = lookupIndex;
2554 }
2555 break;
2556 case DISPATCH_PROPERTYPUT:
2557 case DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF:
2558 {
2559 if (index == -1) {
2560 index = mo->indexOfProperty(name);
2561 if (index == -1)
2562 return res;
2563 }
2564
2565 QMetaProperty property;
2566 if (index < mo->propertyCount())
2567 property = mo->property(index);
2568 if (!property.isWritable())
2569 return DISP_E_MEMBERNOTFOUND;
2570 if (!pDispParams->cArgs)
2571 return DISP_E_PARAMNOTOPTIONAL;
2572 if (pDispParams->cArgs != 1 ||
2573 pDispParams->cNamedArgs != 1 ||
2574 *pDispParams->rgdispidNamedArgs != DISPID_PROPERTYPUT)
2575 return DISP_E_BADPARAMCOUNT;
2576
2577 QVariant var = VARIANTToQVariant(*pDispParams->rgvarg, property.typeName(), property.type());
2578 if (!var.isValid()) {
2579 if (puArgErr)
2580 *puArgErr = 0;
2581 return DISP_E_BADVARTYPE;
2582 }
2583 if (!qt.object->setProperty(property.name(), var)) {
2584 if (puArgErr)
2585 *puArgErr = 0;
2586 return DISP_E_TYPEMISMATCH;
2587 }
2588
2589 res = S_OK;
2590 }
2591 break;
2592
2593 default:
2594 break;
2595 }
2596
2597 // maybe calling a setter? Notify client about changes
2598 switch(wFlags) {
2599 case DISPATCH_METHOD:
2600 case DISPATCH_PROPERTYPUT:
2601 case DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF:
2602 if (m_spAdviseSink || adviseSinks.count()) {
2603 FORMATETC fmt;
2604 fmt.cfFormat = 0;
2605 fmt.ptd = 0;
2606 fmt.dwAspect = DVASPECT_CONTENT;
2607 fmt.lindex = -1;
2608 fmt.tymed = TYMED_NULL;
2609
2610 STGMEDIUM stg;
2611 stg.tymed = TYMED_NULL;
2612 stg.pUnkForRelease = 0;
2613 stg.hBitmap = 0; // initializes the whole union
2614
2615 if (m_spAdviseSink) {
2616 m_spAdviseSink->OnViewChange(DVASPECT_CONTENT, -1);
2617 m_spAdviseSink->OnDataChange(&fmt, &stg);
2618 }
2619 for (int i = 0; i < adviseSinks.count(); ++i) {
2620 adviseSinks.at(i).pAdvSink->OnDataChange(&fmt, &stg);
2621 }
2622 }
2623
2624 dirtyflag = true;
2625 break;
2626 default:
2627 break;
2628 }
2629
2630 if (index != -1 && uniqueIndex)
2631 indexCache.insert(dispidMember, index);
2632
2633 if (exception) {
2634 if (pexcepinfo) {
2635 memset(pexcepinfo, 0, sizeof(EXCEPINFO));
2636
2637 pexcepinfo->wCode = exception->code;
2638 if (!exception->src.isNull())
2639 pexcepinfo->bstrSource = QStringToBSTR(exception->src);
2640 if (!exception->desc.isNull())
2641 pexcepinfo->bstrDescription = QStringToBSTR(exception->desc);
2642 if (!exception->context.isNull()) {
2643 QString context = exception->context;
2644 int contextID = 0;
2645 int br = context.indexOf(QLatin1Char('['));
2646 if (br != -1) {
2647 context = context.mid(br+1);
2648 context = context.left(context.length() - 1);
2649 contextID = context.toInt();
2650
2651 context = exception->context;
2652 context = context.left(br-1);
2653 }
2654 pexcepinfo->bstrHelpFile = QStringToBSTR(context);
2655 pexcepinfo->dwHelpContext = contextID;
2656 }
2657 }
2658 delete exception;
2659 exception = 0;
2660 return DISP_E_EXCEPTION;
2661 } else if (isWidget) {
2662 QSize sizeHint = qt.widget->sizeHint();
2663 if (oldSizeHint != sizeHint) {
2664 updateGeometry();
2665 if (m_spInPlaceSite) {
2666 RECT rect = {0, 0, sizeHint.width(), sizeHint.height()};
2667 m_spInPlaceSite->OnPosRectChange(&rect);
2668 }
2669 }
2670 updateMask();
2671 }
2672
2673 return res;
2674}
2675
2676//**** IConnectionPointContainer
2677/*
2678 Provide the IEnumConnectionPoints implemented in the QAxSignalVec class.
2679*/
2680HRESULT WINAPI QAxServerBase::EnumConnectionPoints(IEnumConnectionPoints **epoints)
2681{
2682 if (!epoints)
2683 return E_POINTER;
2684 *epoints = new QAxSignalVec(points);
2685 (*epoints)->AddRef();
2686 return S_OK;
2687}
2688
2689/*
2690 Provide the IConnectionPoint implemented in the QAxConnection for \a iid.
2691*/
2692HRESULT WINAPI QAxServerBase::FindConnectionPoint(REFIID iid, IConnectionPoint **cpoint)
2693{
2694 if (!cpoint)
2695 return E_POINTER;
2696
2697 IConnectionPoint *cp = points[iid];
2698 *cpoint = cp;
2699 if (cp) {
2700 cp->AddRef();
2701 return S_OK;
2702 }
2703 return CONNECT_E_NOCONNECTION;
2704}
2705
2706//**** IPersistStream
2707/*
2708 \reimp
2709
2710 See documentation of IPersistStorage::IsDirty.
2711*/
2712HRESULT WINAPI QAxServerBase::IsDirty()
2713{
2714 return dirtyflag ? S_OK : S_FALSE;
2715}
2716
2717HRESULT WINAPI QAxServerBase::Load(IStream *pStm)
2718{
2719 STATSTG stat;
2720 HRESULT hres = pStm->Stat(&stat, STATFLAG_DEFAULT);
2721 bool openAsText = false;
2722 QByteArray qtarray;
2723 if (hres == S_OK) {
2724 QString streamName = QString::fromWCharArray(stat.pwcsName);
2725 CoTaskMemFree(stat.pwcsName);
2726 openAsText = streamName == QLatin1String("SomeStreamName");
2727 if (stat.cbSize.HighPart) // more than 4GB - too large!
2728 return S_FALSE;
2729
2730 qtarray.resize(stat.cbSize.LowPart);
2731 ULONG read;
2732 pStm->Read(qtarray.data(), stat.cbSize.LowPart, &read);
2733 } else if (hres == E_NOTIMPL) {
2734 ULONG read = 0;
2735 while (hres != S_FALSE) {
2736 QByteArray arrayRead;
2737 arrayRead.resize(4098);
2738 hres = pStm->Read(arrayRead.data(), arrayRead.size(), &read);
2739 if (hres != S_OK && hres != S_FALSE) {
2740 qtarray.resize(0);
2741 break;
2742 } else if (read == 0)
2743 break;
2744 qtarray.append(arrayRead);
2745 }
2746 }
2747 const QMetaObject *mo = qt.object->metaObject();
2748
2749 QBuffer qtbuffer(&qtarray);
2750 QByteArray mimeType = mo->classInfo(mo->indexOfClassInfo("MIME")).value();
2751 if (!mimeType.isEmpty()) {
2752 mimeType = mimeType.left(mimeType.indexOf(':')); // first type
2753 QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable");
2754 if (axb && axb->readData(&qtbuffer, QString::fromLatin1(mimeType)))
2755 return S_OK;
2756 }
2757
2758 qtbuffer.close(); // resets
2759 qtbuffer.open(openAsText ? (QIODevice::ReadOnly | QIODevice::Text) : QIODevice::ReadOnly);
2760
2761 QDataStream qtstream(&qtbuffer);
2762 int version;
2763 qtstream >> version;
2764 qtstream.setVersion(version);
2765 int more = 0;
2766 qtstream >> more;
2767
2768 while (!qtbuffer.atEnd() && more) {
2769 QString propname;
2770 QVariant value;
2771 qtstream >> propname;
2772 if (propname.isEmpty())
2773 break;
2774 qtstream >> value;
2775 qtstream >> more;
2776
2777 int idx = mo->indexOfProperty(propname.toLatin1());
2778 QMetaProperty property = mo->property(idx);
2779 if (property.isWritable())
2780 qt.object->setProperty(propname.toLatin1(), value);
2781 }
2782 return S_OK;
2783}
2784
2785HRESULT WINAPI QAxServerBase::Save(IStream *pStm, BOOL clearDirty)
2786{
2787 const QMetaObject *mo = qt.object->metaObject();
2788
2789 QBuffer qtbuffer;
2790 bool saved = false;
2791 QByteArray mimeType = mo->classInfo(mo->indexOfClassInfo("MIME")).value();
2792 if (!mimeType.isEmpty()) {
2793 QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable");
2794 saved = axb && axb->writeData(&qtbuffer);
2795 qtbuffer.close();
2796 }
2797
2798 if (!saved) {
2799 qtbuffer.open(QIODevice::WriteOnly);
2800 QDataStream qtstream(&qtbuffer);
2801 qtstream << qtstream.version();
2802
2803 for (int prop = 0; prop < mo->propertyCount(); ++prop) {
2804 if (!isPropertyExposed(prop))
2805 continue;
2806 QMetaProperty metaprop = mo->property(prop);
2807 if (QByteArray(metaprop.typeName()).endsWith('*'))
2808 continue;
2809 QString property = QLatin1String(metaprop.name());
2810 QVariant qvar = qt.object->property(metaprop.name());
2811 if (qvar.isValid()) {
2812 qtstream << int(1);
2813 qtstream << property;
2814 qtstream << qvar;
2815 }
2816 }
2817
2818 qtstream << int(0);
2819 qtbuffer.close();
2820 }
2821
2822 QByteArray qtarray = qtbuffer.buffer();
2823 ULONG written = 0;
2824 const char *data = qtarray.constData();
2825 ULARGE_INTEGER newsize;
2826 newsize.HighPart = 0;
2827 newsize.LowPart = qtarray.size();
2828 pStm->SetSize(newsize);
2829 pStm->Write(data, qtarray.size(), &written);
2830 pStm->Commit(STGC_ONLYIFCURRENT);
2831
2832 if (clearDirty)
2833 dirtyflag = false;
2834 return S_OK;
2835}
2836
2837HRESULT WINAPI QAxServerBase::GetSizeMax(ULARGE_INTEGER *pcbSize)
2838{
2839 const QMetaObject *mo = qt.object->metaObject();
2840
2841 int np = mo->propertyCount();
2842 pcbSize->HighPart = 0;
2843 pcbSize->LowPart = np * 50;
2844
2845 return S_OK;
2846}
2847
2848//**** IPersistStorage
2849
2850HRESULT WINAPI QAxServerBase::InitNew(IStorage *pStg)
2851{
2852 if (initNewCalled)
2853 return CO_E_ALREADYINITIALIZED;
2854
2855 dirtyflag = false;
2856 initNewCalled = true;
2857
2858 m_spStorage = pStg;
2859 if (m_spStorage)
2860 m_spStorage->AddRef();
2861 return S_OK;
2862}
2863
2864HRESULT WINAPI QAxServerBase::Load(IStorage *pStg)
2865{
2866 if (InitNew(pStg) != S_OK)
2867 return CO_E_ALREADYINITIALIZED;
2868
2869 IStream *spStream = 0;
2870 QString streamName = QLatin1String(qt.object->metaObject()->className());
2871 streamName.replace(QLatin1Char(':'), QLatin1Char('.'));
2872 /* Also invalid, but not relevant
2873 streamName.replace(QLatin1Char('/'), QLatin1Char('_'));
2874 streamName.replace(QLatin1Char('\\'), QLatin1Char('_'));
2875 */
2876 streamName += QLatin1String("_Stream4.2");
2877
2878 pStg->OpenStream((const wchar_t *)streamName.utf16(), 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &spStream);
2879 if (!spStream) // support for streams saved with 4.1 and earlier
2880 pStg->OpenStream(L"SomeStreamName", 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &spStream);
2881 if (!spStream)
2882 return E_FAIL;
2883
2884 Load(spStream);
2885 spStream->Release();
2886
2887 return S_OK;
2888}
2889
2890HRESULT WINAPI QAxServerBase::Save(IStorage *pStg, BOOL fSameAsLoad)
2891{
2892 IStream *spStream = 0;
2893 QString streamName = QLatin1String(qt.object->metaObject()->className());
2894 streamName.replace(QLatin1Char(':'), QLatin1Char('.'));
2895 /* Also invalid, but not relevant
2896 streamName.replace(QLatin1Char('/'), QLatin1Char('_'));
2897 streamName.replace(QLatin1Char('\\'), QLatin1Char('_'));
2898 */
2899 streamName += QLatin1String("_Stream4.2");
2900
2901 pStg->CreateStream((const wchar_t *)streamName.utf16(), STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &spStream);
2902 if (!spStream)
2903 return E_FAIL;
2904
2905 Save(spStream, true);
2906
2907 spStream->Release();
2908 return S_OK;
2909}
2910
2911HRESULT WINAPI QAxServerBase::SaveCompleted(IStorage *pStgNew)
2912{
2913 if (pStgNew) {
2914 if (m_spStorage)
2915 m_spStorage->Release();
2916 m_spStorage = pStgNew;
2917 m_spStorage->AddRef();
2918 }
2919 return S_OK;
2920}
2921
2922HRESULT WINAPI QAxServerBase::HandsOffStorage()
2923{
2924 if (m_spStorage) m_spStorage->Release();
2925 m_spStorage = 0;
2926
2927 return S_OK;
2928}
2929
2930//**** IPersistPropertyBag
2931/*
2932 Initialize the properties of the Qt widget.
2933*/
2934HRESULT WINAPI QAxServerBase::InitNew()
2935{
2936 if (initNewCalled)
2937 return CO_E_ALREADYINITIALIZED;
2938
2939 dirtyflag = false;
2940 initNewCalled = true;
2941 return S_OK;
2942}
2943
2944/*
2945 Set the properties of the Qt widget to the values provided in the \a bag.
2946*/
2947HRESULT WINAPI QAxServerBase::Load(IPropertyBag *bag, IErrorLog * /*log*/)
2948{
2949 if (!bag)
2950 return E_POINTER;
2951
2952 if (InitNew() != S_OK)
2953 return E_UNEXPECTED;
2954
2955 bool error = false;
2956 const QMetaObject *mo = qt.object->metaObject();
2957 for (int prop = 0; prop < mo->propertyCount(); ++prop) {
2958 if (!isPropertyExposed(prop))
2959 continue;
2960 QMetaProperty property = mo->property(prop);
2961 const char* pname = property.name();
2962 BSTR bstr = QStringToBSTR(QLatin1String(pname));
2963 VARIANT var;
2964 var.vt = VT_EMPTY;
2965 HRESULT res = bag->Read(bstr, &var, 0);
2966 if (property.isWritable() && var.vt != VT_EMPTY) {
2967 if (res != S_OK || !qt.object->setProperty(pname, VARIANTToQVariant(var, property.typeName(), property.type())))
2968 error = true;
2969 }
2970 SysFreeString(bstr);
2971 }
2972
2973 updateGeometry();
2974
2975 return /*error ? E_FAIL :*/ S_OK;
2976}
2977
2978/*
2979 Save the properties of the Qt widget into the \a bag.
2980*/
2981HRESULT WINAPI QAxServerBase::Save(IPropertyBag *bag, BOOL clearDirty, BOOL /*saveAll*/)
2982{
2983 if (!bag)
2984 return E_POINTER;
2985
2986 if (clearDirty)
2987 dirtyflag = false;
2988 bool error = false;
2989 const QMetaObject *mo = qt.object->metaObject();
2990 for (int prop = 0; prop < mo->propertyCount(); ++prop) {
2991 if (!isPropertyExposed(prop))
2992 continue;
2993 QMetaProperty property = mo->property(prop);
2994 if (QByteArray(property.typeName()).endsWith('*'))
2995 continue;
2996
2997 BSTR bstr = QStringToBSTR(QLatin1String(property.name()));
2998 QVariant qvar = qt.object->property(property.name());
2999 if (!qvar.isValid())
3000 error = true;
3001 VARIANT var;
3002 QVariantToVARIANT(qvar, var);
3003 bag->Write(bstr, &var);
3004 SysFreeString(bstr);
3005 }
3006 return /*error ? E_FAIL :*/ S_OK;
3007}
3008
3009//**** IPersistFile
3010/*
3011*/
3012HRESULT WINAPI QAxServerBase::SaveCompleted(LPCOLESTR fileName)
3013{
3014 if (qt.object->metaObject()->indexOfClassInfo("MIME") == -1)
3015 return E_NOTIMPL;
3016
3017 currentFileName = QString::fromWCharArray(fileName);
3018 return S_OK;
3019}
3020
3021HRESULT WINAPI QAxServerBase::GetCurFile(LPOLESTR *currentFile)
3022{
3023 if (qt.object->metaObject()->indexOfClassInfo("MIME") == -1)
3024 return E_NOTIMPL;
3025
3026 if (currentFileName.isEmpty()) {
3027 *currentFile = 0;
3028 return S_FALSE;
3029 }
3030 IMalloc *malloc = 0;
3031 CoGetMalloc(1, &malloc);
3032 if (!malloc)
3033 return E_OUTOFMEMORY;
3034
3035 *currentFile = static_cast<wchar_t *>(malloc->Alloc(currentFileName.length() * 2));
3036 malloc->Release();
3037 memcpy(*currentFile, currentFileName.unicode(), currentFileName.length() * 2);
3038
3039 return S_OK;
3040}
3041
3042HRESULT WINAPI QAxServerBase::Load(LPCOLESTR fileName, DWORD mode)
3043{
3044 const QMetaObject *mo = qt.object->metaObject();
3045 int mimeIndex = mo->indexOfClassInfo("MIME");
3046 if (mimeIndex == -1)
3047 return E_NOTIMPL;
3048
3049 QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable");
3050 if (!axb) {
3051 qWarning() << class_name << ": No QAxBindable implementation for mime-type handling";
3052 return E_NOTIMPL;
3053 }
3054
3055 QString loadFileName = QString::fromWCharArray(fileName);
3056 QString fileExtension = loadFileName.mid(loadFileName.lastIndexOf(QLatin1Char('.')) + 1);
3057 QFile file(loadFileName);
3058
3059 QString mimeType = QLatin1String(mo->classInfo(mimeIndex).value());
3060 QStringList mimeTypes = mimeType.split(QLatin1Char(';'));
3061 for (int m = 0; m < mimeTypes.count(); ++m) {
3062 QString mime = mimeTypes.at(m);
3063 if (mime.count(QLatin1Char(':')) != 2) {
3064 qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME";
3065 continue;
3066 }
3067
3068 mimeType = mime.left(mimeType.indexOf(QLatin1Char(':'))); // first type
3069 if (mimeType.isEmpty()) {
3070 qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME";
3071 continue;
3072 }
3073 QString mimeExtension = mime.mid(mimeType.length() + 1);
3074 mimeExtension = mimeExtension.left(mimeExtension.indexOf(QLatin1Char(':')));
3075 if (mimeExtension != fileExtension)
3076 continue;
3077
3078 if (axb->readData(&file, mimeType)) {
3079 currentFileName = loadFileName;
3080 return S_OK;
3081 }
3082 }
3083
3084 return E_FAIL;
3085}
3086
3087HRESULT WINAPI QAxServerBase::Save(LPCOLESTR fileName, BOOL fRemember)
3088{
3089 const QMetaObject *mo = qt.object->metaObject();
3090 int mimeIndex = mo->indexOfClassInfo("MIME");
3091 if (mimeIndex == -1)
3092 return E_NOTIMPL;
3093
3094 QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable");
3095 if (!axb) {
3096 qWarning() << class_name << ": No QAxBindable implementation for mime-type handling";
3097 return E_NOTIMPL;
3098 }
3099
3100 QString saveFileName = QString::fromWCharArray(fileName);
3101 QString fileExtension = saveFileName.mid(saveFileName.lastIndexOf(QLatin1Char('.')) + 1);
3102 QFile file(saveFileName);
3103
3104 QString mimeType = QLatin1String(mo->classInfo(mimeIndex).value());
3105 QStringList mimeTypes = mimeType.split(QLatin1Char(';'));
3106 for (int m = 0; m < mimeTypes.count(); ++m) {
3107 QString mime = mimeTypes.at(m);
3108 if (mime.count(QLatin1Char(':')) != 2) {
3109 qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME";
3110 continue;
3111 }
3112 mimeType = mime.left(mimeType.indexOf(QLatin1Char(':'))); // first type
3113 if (mimeType.isEmpty()) {
3114 qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME";
3115 continue;
3116 }
3117 QString mimeExtension = mime.mid(mimeType.length() + 1);
3118 mimeExtension = mimeExtension.left(mimeExtension.indexOf(QLatin1Char(':')));
3119 if (mimeExtension != fileExtension)
3120 continue;
3121 if (axb->writeData(&file)) {
3122 if (fRemember)
3123 currentFileName = saveFileName;
3124 return S_OK;
3125 }
3126 }
3127 return E_FAIL;
3128}
3129
3130//**** IViewObject
3131/*
3132 Draws the widget into the provided device context.
3133*/
3134HRESULT WINAPI QAxServerBase::Draw(DWORD dwAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
3135 HDC hicTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL /*lprcWBounds*/,
3136 BOOL(__stdcall* /*pfnContinue*/)(ULONG_PTR), ULONG_PTR /*dwContinue*/)
3137{
3138 if (!lprcBounds)
3139 return E_INVALIDARG;
3140
3141 internalCreate();
3142 if (!isWidget || !qt.widget)
3143 return OLE_E_BLANK;
3144
3145 switch (dwAspect) {
3146 case DVASPECT_CONTENT:
3147 case DVASPECT_OPAQUE:
3148 case DVASPECT_TRANSPARENT:
3149 break;
3150 default:
3151 return DV_E_DVASPECT;
3152 }
3153 if (!ptd)
3154 hicTargetDev = 0;
3155
3156 bool bDeleteDC = false;
3157 if (!hicTargetDev) {
3158 hicTargetDev = ::CreateDC(L"DISPLAY", NULL, NULL, NULL);
3159 bDeleteDC = (hicTargetDev != hdcDraw);
3160 }
3161
3162 RECTL rc = *lprcBounds;
3163 bool bMetaFile = GetDeviceCaps(hdcDraw, TECHNOLOGY) == DT_METAFILE;
3164 if (!bMetaFile)
3165 ::LPtoDP(hicTargetDev, (LPPOINT)&rc, 2);
3166
3167 QPixmap pm = QPixmap::grabWidget(qt.widget);
3168 HBITMAP hbm = pm.toWinHBITMAP();
3169 HDC hdc = CreateCompatibleDC(0);
3170 SelectObject(hdc, hbm);
3171 ::StretchBlt(hdcDraw, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0,pm.width(), pm.height(), SRCCOPY);
3172 DeleteDC(hdc);
3173 DeleteObject(hbm);
3174
3175 if (bDeleteDC)
3176 DeleteDC(hicTargetDev);
3177
3178 return S_OK;
3179}
3180
3181/*
3182 Not implemented.
3183*/
3184HRESULT WINAPI QAxServerBase::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
3185 HDC hicTargetDev, LOGPALETTE **ppColorSet)
3186{
3187 return E_NOTIMPL;
3188}
3189
3190/*
3191 Not implemented.
3192*/
3193HRESULT WINAPI QAxServerBase::Freeze(DWORD dwAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
3194{
3195 return E_NOTIMPL;
3196}
3197
3198/*
3199 Not implemented.
3200*/
3201HRESULT WINAPI QAxServerBase::Unfreeze(DWORD dwFreeze)
3202{
3203 return E_NOTIMPL;
3204}
3205
3206/*
3207 Stores the provided advise sink.
3208*/
3209HRESULT WINAPI QAxServerBase::SetAdvise(DWORD /*aspects*/, DWORD /*advf*/, IAdviseSink *pAdvSink)
3210{
3211 if (m_spAdviseSink) m_spAdviseSink->Release();
3212
3213 m_spAdviseSink = pAdvSink;
3214 if (m_spAdviseSink) m_spAdviseSink->AddRef();
3215 return S_OK;
3216}
3217
3218/*
3219 Returns the advise sink.
3220*/
3221HRESULT WINAPI QAxServerBase::GetAdvise(DWORD* /*aspects*/, DWORD* /*advf*/, IAdviseSink **ppAdvSink)
3222{
3223 if (!ppAdvSink)
3224 return E_POINTER;
3225
3226 *ppAdvSink = m_spAdviseSink;
3227 if (*ppAdvSink)
3228 (*ppAdvSink)->AddRef();
3229 return S_OK;
3230}
3231
3232//**** IViewObject2
3233/*
3234 Returns the current size ONLY if the widget has already been sized.
3235*/
3236HRESULT WINAPI QAxServerBase::GetExtent(DWORD dwAspect, LONG /*lindex*/, DVTARGETDEVICE* /*ptd*/, LPSIZEL lpsizel)
3237{
3238 if (!isWidget || !qt.widget || !qt.widget->testAttribute(Qt::WA_Resized))
3239 return OLE_E_BLANK;
3240
3241 return GetExtent(dwAspect, lpsizel);
3242}
3243
3244//**** IOleControl
3245/*
3246 Not implemented.
3247*/
3248HRESULT WINAPI QAxServerBase::GetControlInfo(LPCONTROLINFO)
3249{
3250 return E_NOTIMPL;
3251}
3252
3253/*
3254 Turns event firing on and off.
3255*/
3256HRESULT WINAPI QAxServerBase::FreezeEvents(BOOL bFreeze)
3257{
3258 // member of CComControl
3259 if (bFreeze)
3260 freezeEvents++;
3261 else
3262 freezeEvents--;
3263
3264 return S_OK;
3265}
3266
3267/*
3268 Not implemented.
3269*/
3270HRESULT WINAPI QAxServerBase::OnMnemonic(LPMSG)
3271{
3272 return E_NOTIMPL;
3273}
3274
3275/*
3276 Update the ambient properties of the Qt widget.
3277*/
3278HRESULT WINAPI QAxServerBase::OnAmbientPropertyChange(DISPID dispID)
3279{
3280 if (!m_spClientSite || !theObject)
3281 return S_OK;
3282
3283 IDispatch *disp = 0;
3284 m_spClientSite->QueryInterface(IID_IDispatch, (void**)&disp);
3285 if (!disp)
3286 return S_OK;
3287
3288 VARIANT var;
3289 VariantInit(&var);
3290 DISPPARAMS params = { 0, 0, 0, 0 };
3291 disp->Invoke(dispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &params, &var, 0, 0);
3292 disp->Release();
3293 disp = 0;
3294
3295 switch(dispID) {
3296 case DISPID_AMBIENT_APPEARANCE:
3297 break;
3298 case DISPID_AMBIENT_AUTOCLIP:
3299 break;
3300 case DISPID_AMBIENT_BACKCOLOR:
3301 case DISPID_AMBIENT_FORECOLOR:
3302 if (isWidget) {
3303 long rgb;
3304 if (var.vt == VT_UI4)
3305 rgb = var.ulVal;
3306 else if (var.vt == VT_I4)
3307 rgb = var.lVal;
3308 else
3309 break;
3310 QPalette pal = qt.widget->palette();
3311 pal.setColor(dispID == DISPID_AMBIENT_BACKCOLOR ? QPalette::Window : QPalette::WindowText,
3312 OLEColorToQColor(rgb));
3313 qt.widget->setPalette(pal);
3314 }
3315 break;
3316 case DISPID_AMBIENT_DISPLAYASDEFAULT:
3317 break;
3318 case DISPID_AMBIENT_DISPLAYNAME:
3319 if (var.vt != VT_BSTR || !isWidget)
3320 break;
3321 qt.widget->setWindowTitle(QString::fromWCharArray(var.bstrVal));
3322 break;
3323 case DISPID_AMBIENT_FONT:
3324 if (var.vt != VT_DISPATCH || !isWidget)
3325 break;
3326 {
3327 QVariant qvar = VARIANTToQVariant(var, "QFont", QVariant::Font);
3328 QFont qfont = qVariantValue<QFont>(qvar);
3329 qt.widget->setFont(qfont);
3330 }
3331 break;
3332 case DISPID_AMBIENT_LOCALEID:
3333 break;
3334 case DISPID_AMBIENT_MESSAGEREFLECT:
3335 if (var.vt != VT_BOOL)
3336 break;
3337 if (var.boolVal)
3338 qt.widget->installEventFilter(this);
3339 else
3340 qt.widget->removeEventFilter(this);
3341 break;
3342 case DISPID_AMBIENT_PALETTE:
3343 break;
3344 case DISPID_AMBIENT_SCALEUNITS:
3345 break;
3346 case DISPID_AMBIENT_SHOWGRABHANDLES:
3347 break;
3348 case DISPID_AMBIENT_SHOWHATCHING:
3349 break;
3350 case DISPID_AMBIENT_SUPPORTSMNEMONICS:
3351 break;
3352 case DISPID_AMBIENT_TEXTALIGN:
3353 break;
3354 case DISPID_AMBIENT_UIDEAD:
3355 if (var.vt != VT_BOOL || !isWidget)
3356 break;
3357 qt.widget->setEnabled(!var.boolVal);
3358 break;
3359 case DISPID_AMBIENT_USERMODE:
3360 if (var.vt != VT_BOOL)
3361 break;
3362 inDesignMode = !var.boolVal;
3363 break;
3364 case DISPID_AMBIENT_RIGHTTOLEFT:
3365 if (var.vt != VT_BOOL)
3366 break;
3367 qApp->setLayoutDirection(var.boolVal?Qt::RightToLeft:Qt::LeftToRight);
3368 break;
3369 }
3370
3371 return S_OK;
3372}
3373
3374//**** IOleWindow
3375/*
3376 Returns the HWND of the control.
3377*/
3378HRESULT WINAPI QAxServerBase::GetWindow(HWND *pHwnd)
3379{
3380 if (!pHwnd)
3381 return E_POINTER;
3382 *pHwnd = m_hWnd;
3383 return S_OK;
3384}
3385
3386/*
3387 Enters What's This mode.
3388*/
3389HRESULT WINAPI QAxServerBase::ContextSensitiveHelp(BOOL fEnterMode)
3390{
3391 if (fEnterMode)
3392 QWhatsThis::enterWhatsThisMode();
3393 else
3394 QWhatsThis::leaveWhatsThisMode();
3395 return S_OK;
3396}
3397
3398//**** IOleInPlaceObject
3399/*
3400 Deactivates the control in place.
3401*/
3402HRESULT WINAPI QAxServerBase::InPlaceDeactivate()
3403{
3404 if (!isInPlaceActive)
3405 return S_OK;
3406 UIDeactivate();
3407
3408 isInPlaceActive = false;
3409
3410 // if we have a window, tell it to go away.
3411 if (m_hWnd) {
3412 if (::IsWindow(m_hWnd))
3413 ::DestroyWindow(m_hWnd);
3414 m_hWnd = 0;
3415 }
3416
3417 if (m_spInPlaceSite)
3418 m_spInPlaceSite->OnInPlaceDeactivate();
3419
3420 return S_OK;
3421}
3422
3423/*
3424 Deactivates the control's user interface.
3425*/
3426HRESULT WINAPI QAxServerBase::UIDeactivate()
3427{
3428 // if we're not UIActive, not much to do.
3429 if (!isUIActive || !m_spInPlaceSite)
3430 return S_OK;
3431
3432 isUIActive = false;
3433
3434 // notify frame windows, if appropriate, that we're no longer ui-active.
3435 HWND hwndParent;
3436 if (m_spInPlaceSite->GetWindow(&hwndParent) == S_OK) {
3437 if (m_spInPlaceFrame) m_spInPlaceFrame->Release();
3438 m_spInPlaceFrame = 0;
3439 IOleInPlaceUIWindow *spInPlaceUIWindow = 0;
3440 RECT rcPos, rcClip;
3441 OLEINPLACEFRAMEINFO frameInfo;
3442 frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
3443
3444 m_spInPlaceSite->GetWindowContext(&m_spInPlaceFrame, &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo);
3445 if (spInPlaceUIWindow) {
3446 spInPlaceUIWindow->SetActiveObject(0, 0);
3447 spInPlaceUIWindow->Release();
3448 }
3449 if (m_spInPlaceFrame) {
3450 removeMenu();
3451 if (menuBar) {
3452 menuBar->removeEventFilter(this);
3453 menuBar = 0;
3454 }
3455 if (statusBar) {
3456 statusBar->removeEventFilter(this);
3457 const int index = statusBar->metaObject()->indexOfSignal("messageChanged(QString)");
3458 QMetaObject::disconnect(statusBar, index, this, -1);
3459 statusBar = 0;
3460 }
3461 m_spInPlaceFrame->SetActiveObject(0, 0);
3462 m_spInPlaceFrame->Release();
3463 m_spInPlaceFrame = 0;
3464 }
3465 }
3466 // we don't need to explicitly release the focus here since somebody
3467 // else grabbing the focus is usually why we are getting called at all
3468 m_spInPlaceSite->OnUIDeactivate(false);
3469
3470 return S_OK;
3471}
3472
3473/*
3474 Positions the control, and applies requested clipping.
3475*/
3476HRESULT WINAPI QAxServerBase::SetObjectRects(LPCRECT prcPos, LPCRECT prcClip)
3477{
3478 if (prcPos == 0 || prcClip == 0)
3479 return E_POINTER;
3480
3481 if (m_hWnd) {
3482 // the container wants us to clip, so figure out if we really need to
3483 RECT rcIXect;
3484 BOOL b = IntersectRect(&rcIXect, prcPos, prcClip);
3485 HRGN tempRgn = 0;
3486 if (b && !EqualRect(&rcIXect, prcPos)) {
3487 OffsetRect(&rcIXect, -(prcPos->left), -(prcPos->top));
3488 tempRgn = CreateRectRgnIndirect(&rcIXect);
3489 }
3490
3491 ::SetWindowRgn(m_hWnd, tempRgn, true);
3492 ::SetWindowPos(m_hWnd, 0, prcPos->left, prcPos->top,
3493 prcPos->right - prcPos->left, prcPos->bottom - prcPos->top,
3494 SWP_NOZORDER | SWP_NOACTIVATE);
3495 }
3496
3497 //Save the new extent.
3498 m_currentExtent.rwidth() = qBound(qt.widget->minimumWidth(), int(prcPos->right - prcPos->left), qt.widget->maximumWidth());
3499 m_currentExtent.rheight() = qBound(qt.widget->minimumHeight(), int(prcPos->bottom - prcPos->top), qt.widget->maximumHeight());
3500
3501 return S_OK;
3502}
3503
3504/*
3505 Not implemented.
3506*/
3507HRESULT WINAPI QAxServerBase::ReactivateAndUndo()
3508{
3509 return E_NOTIMPL;
3510}
3511
3512//**** IOleInPlaceActiveObject
3513
3514Q_GUI_EXPORT int qt_translateKeyCode(int);
3515
3516HRESULT WINAPI QAxServerBase::TranslateAcceleratorW(MSG *pMsg)
3517{
3518 if (pMsg->message != WM_KEYDOWN || !isWidget)
3519 return S_FALSE;
3520
3521 DWORD dwKeyMod = 0;
3522 if (::GetKeyState(VK_SHIFT) < 0)
3523 dwKeyMod |= 1; // KEYMOD_SHIFT
3524 if (::GetKeyState(VK_CONTROL) < 0)
3525 dwKeyMod |= 2; // KEYMOD_CONTROL
3526 if (::GetKeyState(VK_MENU) < 0)
3527 dwKeyMod |= 4; // KEYMOD_ALT
3528
3529 switch (LOWORD(pMsg->wParam)) {
3530 case VK_TAB:
3531 if (isUIActive) {
3532 bool shift = ::GetKeyState(VK_SHIFT) < 0;
3533 bool giveUp = true;
3534 QWidget *curFocus = qt.widget->focusWidget();
3535 if (curFocus) {
3536 if (shift) {
3537 if (!curFocus->isWindow()) {
3538 QWidget *nextFocus = curFocus->nextInFocusChain();
3539 QWidget *prevFocus = 0;
3540 QWidget *topLevel = 0;
3541 while (nextFocus != curFocus) {
3542 if (nextFocus->focusPolicy() & Qt::TabFocus) {
3543 prevFocus = nextFocus;
3544 topLevel = 0;
3545 } else if (nextFocus->isWindow()) {
3546 topLevel = nextFocus;
3547 }
3548 nextFocus = nextFocus->nextInFocusChain();
3549 }
3550
3551 if (!topLevel) {
3552 giveUp = false;
3553 ((HackWidget*)curFocus)->focusNextPrevChild(false);
3554 curFocus->window()->setAttribute(Qt::WA_KeyboardFocusChange);
3555 }
3556 }
3557 } else {
3558 QWidget *nextFocus = curFocus;
3559 while (1) {
3560 nextFocus = nextFocus->nextInFocusChain();
3561 if (nextFocus->isWindow())
3562 break;
3563 if (nextFocus->focusPolicy() & Qt::TabFocus) {
3564 giveUp = false;
3565 ((HackWidget*)curFocus)->focusNextPrevChild(true);
3566 curFocus->window()->setAttribute(Qt::WA_KeyboardFocusChange);
3567 break;
3568 }
3569 }
3570 }
3571 }
3572 if (giveUp) {
3573 HWND hwnd = ::GetParent(m_hWnd);
3574 ::SetFocus(hwnd);
3575 } else {
3576 return S_OK;
3577 }
3578
3579 }
3580 break;
3581
3582 case VK_LEFT:
3583 case VK_RIGHT:
3584 case VK_UP:
3585 case VK_DOWN:
3586 if (isUIActive)
3587 return S_FALSE;
3588 break;
3589
3590 default:
3591 if (isUIActive && qt.widget->focusWidget()) {
3592 int state = Qt::NoButton;
3593 if (dwKeyMod & 1)
3594 state |= Qt::ShiftModifier;
3595 if (dwKeyMod & 2)
3596 state |= Qt::ControlModifier;
3597 if (dwKeyMod & 4)
3598 state |= Qt::AltModifier;
3599
3600 int key = pMsg->wParam;
3601 if (!(key >= 'A' && key <= 'Z') && !(key >= '0' && key <= '9'))
3602 key = qt_translateKeyCode(pMsg->wParam);
3603
3604 QKeyEvent override(QEvent::ShortcutOverride, key, (Qt::KeyboardModifiers)state);
3605 override.ignore();
3606 QApplication::sendEvent(qt.widget->focusWidget(), &override);
3607 if (override.isAccepted())
3608 return S_FALSE;
3609 }
3610 break;
3611 }
3612
3613 if (!m_spClientSite)
3614 return S_FALSE;
3615
3616 IOleControlSite *controlSite = 0;
3617 m_spClientSite->QueryInterface(IID_IOleControlSite, (void**)&controlSite);
3618 if (!controlSite)
3619 return S_FALSE;
3620 bool resetUserData = false;
3621 // set server type in the user-data of the window.
3622#ifdef GWLP_USERDATA
3623 LONG_PTR serverType = QAX_INPROC_SERVER;
3624#else
3625 LONG serverType = QAX_INPROC_SERVER;
3626#endif
3627 if (qAxOutProcServer)
3628 serverType = QAX_OUTPROC_SERVER;
3629#ifdef GWLP_USERDATA
3630 LONG_PTR oldData = SetWindowLongPtr(pMsg->hwnd, GWLP_USERDATA, serverType);
3631#else
3632 LONG oldData = SetWindowLong(pMsg->hwnd, GWL_USERDATA, serverType);
3633#endif
3634 HRESULT hres = controlSite->TranslateAcceleratorW(pMsg, dwKeyMod);
3635 controlSite->Release();
3636 // reset the user-data for the window.
3637#ifdef GWLP_USERDATA
3638 SetWindowLongPtr(pMsg->hwnd, GWLP_USERDATA, oldData);
3639#else
3640 SetWindowLong(pMsg->hwnd, GWL_USERDATA, oldData);
3641#endif
3642 return hres;
3643}
3644
3645HRESULT WINAPI QAxServerBase::TranslateAcceleratorA(MSG *pMsg)
3646{
3647 return TranslateAcceleratorW(pMsg);
3648}
3649
3650HRESULT WINAPI QAxServerBase::OnFrameWindowActivate(BOOL fActivate)
3651{
3652 if (fActivate) {
3653 if (wasUIActive)
3654 ::SetFocus(m_hWnd);
3655 } else {
3656 wasUIActive = isUIActive;
3657 }
3658 return S_OK;
3659}
3660
3661HRESULT WINAPI QAxServerBase::OnDocWindowActivate(BOOL fActivate)
3662{
3663 return S_OK;
3664}
3665
3666HRESULT WINAPI QAxServerBase::ResizeBorder(LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fFrameWindow)
3667{
3668 return S_OK;
3669}
3670
3671HRESULT WINAPI QAxServerBase::EnableModeless(BOOL fEnable)
3672{
3673 if (!isWidget)
3674 return S_OK;
3675
3676 EnableWindow(qt.widget->winId(), fEnable);
3677 return S_OK;
3678}
3679
3680//**** IOleObject
3681
3682static inline LPOLESTR QStringToOLESTR(const QString &qstring)
3683{
3684 LPOLESTR olestr = (wchar_t*)CoTaskMemAlloc(qstring.length()*2+2);
3685 memcpy(olestr, (ushort*)qstring.unicode(), qstring.length()*2);
3686 olestr[qstring.length()] = 0;
3687 return olestr;
3688}
3689
3690/*
3691 \reimp
3692
3693 See documentation of IOleObject::GetUserType.
3694*/
3695HRESULT WINAPI QAxServerBase::GetUserType(DWORD dwFormOfType, LPOLESTR *pszUserType)
3696{
3697 if (!pszUserType)
3698 return E_POINTER;
3699
3700 switch (dwFormOfType) {
3701 case USERCLASSTYPE_FULL:
3702 *pszUserType = QStringToOLESTR(class_name);
3703 break;
3704 case USERCLASSTYPE_SHORT:
3705 if (!qt.widget || !isWidget || qt.widget->windowTitle().isEmpty())
3706 *pszUserType = QStringToOLESTR(class_name);
3707 else
3708 *pszUserType = QStringToOLESTR(qt.widget->windowTitle());
3709 break;
3710 case USERCLASSTYPE_APPNAME:
3711 *pszUserType = QStringToOLESTR(qApp->objectName());
3712 break;
3713 }
3714
3715 return S_OK;
3716}
3717
3718/*
3719 Returns the status flags registered for this control.
3720*/
3721HRESULT WINAPI QAxServerBase::GetMiscStatus(DWORD dwAspect, DWORD *pdwStatus)
3722{
3723 return OleRegGetMiscStatus(qAxFactory()->classID(class_name), dwAspect, pdwStatus);
3724}
3725
3726/*
3727 Stores the provided advise sink.
3728*/
3729HRESULT WINAPI QAxServerBase::Advise(IAdviseSink* pAdvSink, DWORD* pdwConnection)
3730{
3731 *pdwConnection = adviseSinks.count() + 1;
3732 STATDATA data = { {0, 0, DVASPECT_CONTENT, -1, TYMED_NULL} , 0, pAdvSink, *pdwConnection };
3733 adviseSinks.append(data);
3734 pAdvSink->AddRef();
3735 return S_OK;
3736}
3737
3738/*
3739 Closes the control.
3740*/
3741HRESULT WINAPI QAxServerBase::Close(DWORD dwSaveOption)
3742{
3743 if (dwSaveOption != OLECLOSE_NOSAVE && m_spClientSite)
3744 m_spClientSite->SaveObject();
3745 if (isInPlaceActive) {
3746 HRESULT hr = InPlaceDeactivate();
3747 if (FAILED(hr))
3748 return hr;
3749 }
3750 if (m_hWnd) {
3751 if (IsWindow(m_hWnd))
3752 DestroyWindow(m_hWnd);
3753 m_hWnd = 0;
3754 if (m_spClientSite)
3755 m_spClientSite->OnShowWindow(false);
3756 }
3757
3758 if (m_spInPlaceSite) m_spInPlaceSite->Release();
3759 m_spInPlaceSite = 0;
3760
3761 if (m_spAdviseSink)
3762 m_spAdviseSink->OnClose();
3763 for (int i = 0; i < adviseSinks.count(); ++i) {
3764 adviseSinks.at(i).pAdvSink->OnClose();
3765 }
3766
3767 return S_OK;
3768}
3769
3770bool qax_disable_inplaceframe = true;
3771
3772/*
3773 Executes the steps to activate the control.
3774*/
3775HRESULT QAxServerBase::internalActivate()
3776{
3777 if (!m_spClientSite)
3778 return S_OK;
3779 if (!m_spInPlaceSite)
3780 m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (void**)&m_spInPlaceSite);
3781 if (!m_spInPlaceSite)
3782 return E_FAIL;
3783
3784 HRESULT hr = E_FAIL;
3785 if (!isInPlaceActive) {
3786 BOOL bNoRedraw = false;
3787 hr = m_spInPlaceSite->CanInPlaceActivate();
3788 if (FAILED(hr))
3789 return hr;
3790 if (hr != S_OK)
3791 return E_FAIL;
3792 m_spInPlaceSite->OnInPlaceActivate();
3793 }
3794
3795 isInPlaceActive = true;
3796 OnAmbientPropertyChange(DISPID_AMBIENT_USERMODE);
3797
3798 if (isWidget) {
3799 IOleInPlaceUIWindow *spInPlaceUIWindow = 0;
3800 HWND hwndParent;
3801 if (m_spInPlaceSite->GetWindow(&hwndParent) == S_OK) {
3802 // get location in the parent window, as well as some information about the parent
3803 if (m_spInPlaceFrame) m_spInPlaceFrame->Release();
3804 m_spInPlaceFrame = 0;
3805 RECT rcPos, rcClip;
3806 OLEINPLACEFRAMEINFO frameInfo;
3807 frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
3808 m_spInPlaceSite->GetWindowContext(&m_spInPlaceFrame, &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo);
3809 if (m_hWnd) {
3810 ::ShowWindow(m_hWnd, SW_SHOW);
3811 if (!::IsChild(m_hWnd, ::GetFocus()) && qt.widget->focusPolicy() != Qt::NoFocus)
3812 ::SetFocus(m_hWnd);
3813 } else {
3814 create(hwndParent, rcPos);
3815 }
3816 }
3817
3818 // Gone active by now, take care of UIACTIVATE
3819 canTakeFocus = qt.widget->focusPolicy() != Qt::NoFocus && !inDesignMode;
3820 if (!canTakeFocus && !inDesignMode) {
3821 QList<QWidget*> widgets = qFindChildren<QWidget*>(qt.widget);
3822 for (int w = 0; w < widgets.count(); ++w) {
3823 QWidget *widget = widgets[w];
3824 canTakeFocus = widget->focusPolicy() != Qt::NoFocus;
3825 if (canTakeFocus)
3826 break;
3827 }
3828 }
3829 if (!isUIActive && canTakeFocus) {
3830 isUIActive = true;
3831 hr = m_spInPlaceSite->OnUIActivate();
3832 if (FAILED(hr)) {
3833 if (m_spInPlaceFrame) m_spInPlaceFrame->Release();
3834 m_spInPlaceFrame = 0;
3835 if (spInPlaceUIWindow) spInPlaceUIWindow->Release();
3836 return hr;
3837 }
3838
3839 if (isInPlaceActive) {
3840 if (!::IsChild(m_hWnd, ::GetFocus()))
3841 ::SetFocus(m_hWnd);
3842 }
3843
3844 if (m_spInPlaceFrame) {
3845 hr = m_spInPlaceFrame->SetActiveObject(this, QStringToBSTR(class_name));
3846 if (!FAILED(hr)) {
3847 menuBar = (qt.widget && !qax_disable_inplaceframe) ? qFindChild<QMenuBar*>(qt.widget) : 0;
3848 if (menuBar && !menuBar->isVisible()) {
3849 createMenu(menuBar);
3850 menuBar->hide();
3851 menuBar->installEventFilter(this);
3852 }
3853 statusBar = qt.widget ? qFindChild<QStatusBar*>(qt.widget) : 0;
3854 if (statusBar && !statusBar->isVisible()) {
3855 const int index = statusBar->metaObject()->indexOfSignal("messageChanged(QString)");
3856 QMetaObject::connect(statusBar, index, this, -1);
3857 statusBar->hide();
3858 statusBar->installEventFilter(this);
3859 }
3860 }
3861 }
3862 if (spInPlaceUIWindow) {
3863 spInPlaceUIWindow->SetActiveObject(this, QStringToBSTR(class_name));
3864 spInPlaceUIWindow->SetBorderSpace(0);
3865 }
3866 }
3867 if (spInPlaceUIWindow) spInPlaceUIWindow->Release();
3868 ShowWindow(m_hWnd, SW_NORMAL);
3869 }
3870
3871 m_spClientSite->ShowObject();
3872
3873 return S_OK;
3874}
3875
3876/*
3877 Executes the "verb" \a iVerb.
3878*/
3879HRESULT WINAPI QAxServerBase::DoVerb(LONG iVerb, LPMSG /*lpmsg*/, IOleClientSite* /*pActiveSite*/, LONG /*lindex*/,
3880 HWND /*hwndParent*/, LPCRECT /*prcPosRect*/)
3881{
3882 HRESULT hr = E_NOTIMPL;
3883 switch (iVerb)
3884 {
3885 case OLEIVERB_SHOW:
3886 hr = internalActivate();
3887 if (SUCCEEDED(hr))
3888 hr = S_OK;
3889 break;
3890
3891 case OLEIVERB_PRIMARY:
3892 case OLEIVERB_INPLACEACTIVATE:
3893 hr = internalActivate();
3894 if (SUCCEEDED(hr)) {
3895 hr = S_OK;
3896 update();
3897 }
3898 break;
3899
3900 case OLEIVERB_UIACTIVATE:
3901 if (!isUIActive) {
3902 hr = internalActivate();
3903 if (SUCCEEDED(hr))
3904 hr = S_OK;
3905 }
3906 break;
3907
3908 case OLEIVERB_HIDE:
3909 UIDeactivate();
3910 if (m_hWnd)
3911 ::ShowWindow(m_hWnd, SW_HIDE);
3912 hr = S_OK;
3913 return hr;
3914
3915 default:
3916 break;
3917 }
3918 return hr;
3919}
3920
3921/*
3922 Not implemented.
3923*/
3924HRESULT WINAPI QAxServerBase::EnumAdvise(IEnumSTATDATA** /*ppenumAdvise*/)
3925{
3926 return E_NOTIMPL;
3927}
3928
3929/*
3930 Returns an enumerator for the verbs registered for this class.
3931*/
3932HRESULT WINAPI QAxServerBase::EnumVerbs(IEnumOLEVERB** ppEnumOleVerb)
3933{
3934 if (!ppEnumOleVerb)
3935 return E_POINTER;
3936 return OleRegEnumVerbs(qAxFactory()->classID(class_name), ppEnumOleVerb);
3937}
3938
3939/*
3940 Returns the current client site..
3941*/
3942HRESULT WINAPI QAxServerBase::GetClientSite(IOleClientSite** ppClientSite)
3943{
3944 if (!ppClientSite)
3945 return E_POINTER;
3946 *ppClientSite = m_spClientSite;
3947 if (*ppClientSite)
3948 (*ppClientSite)->AddRef();
3949 return S_OK;
3950}
3951
3952/*
3953 Not implemented.
3954*/
3955HRESULT WINAPI QAxServerBase::GetClipboardData(DWORD, IDataObject**)
3956{
3957 return E_NOTIMPL;
3958}
3959
3960/*
3961 Returns the current extent.
3962*/
3963HRESULT WINAPI QAxServerBase::GetExtent(DWORD dwDrawAspect, SIZEL* psizel)
3964{
3965 if (dwDrawAspect != DVASPECT_CONTENT || !isWidget || !qt.widget)
3966 return E_FAIL;
3967 if (!psizel)
3968 return E_POINTER;
3969
3970 psizel->cx = MAP_PIX_TO_LOGHIM(m_currentExtent.width(), qt.widget->logicalDpiX());
3971 psizel->cy = MAP_PIX_TO_LOGHIM(m_currentExtent.height(), qt.widget->logicalDpiY());
3972 return S_OK;
3973}
3974
3975/*
3976 Not implemented.
3977*/
3978HRESULT WINAPI QAxServerBase::GetMoniker(DWORD, DWORD, IMoniker** )
3979{
3980 return E_NOTIMPL;
3981}
3982
3983/*
3984 Returns the CLSID of this class.
3985*/
3986HRESULT WINAPI QAxServerBase::GetUserClassID(CLSID* pClsid)
3987{
3988 if (!pClsid)
3989 return E_POINTER;
3990 *pClsid = qAxFactory()->classID(class_name);
3991 return S_OK;
3992}
3993
3994/*
3995 Not implemented.
3996*/
3997HRESULT WINAPI QAxServerBase::InitFromData(IDataObject*, BOOL, DWORD)
3998{
3999 return E_NOTIMPL;
4000}
4001
4002/*
4003 Not implemented.
4004*/
4005HRESULT WINAPI QAxServerBase::IsUpToDate()
4006{
4007 return S_OK;
4008}
4009
4010/*
4011 Stores the client site.
4012*/
4013HRESULT WINAPI QAxServerBase::SetClientSite(IOleClientSite* pClientSite)
4014{
4015 // release all client site interfaces
4016 if (m_spClientSite) m_spClientSite->Release();
4017 if (m_spInPlaceSite) m_spInPlaceSite->Release();
4018 m_spInPlaceSite = 0;
4019 if (m_spInPlaceFrame) m_spInPlaceFrame->Release();
4020 m_spInPlaceFrame = 0;
4021
4022 m_spClientSite = pClientSite;
4023 if (m_spClientSite) {
4024 m_spClientSite->AddRef();
4025 m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (void **)&m_spInPlaceSite);
4026 }
4027
4028 return S_OK;
4029}
4030
4031/*
4032 Not implemented.
4033*/
4034HRESULT WINAPI QAxServerBase::SetColorScheme(LOGPALETTE*)
4035{
4036 return E_NOTIMPL;
4037}
4038
4039
4040#ifdef QT_DLL // avoid conflict with symbol in static lib
4041bool qt_sendSpontaneousEvent(QObject *o, QEvent *e)
4042{
4043 return QCoreApplication::sendSpontaneousEvent(o, e);
4044}
4045#endif
4046
4047/*
4048 Tries to set the size of the control.
4049*/
4050HRESULT WINAPI QAxServerBase::SetExtent(DWORD dwDrawAspect, SIZEL* psizel)
4051{
4052 if (dwDrawAspect != DVASPECT_CONTENT)
4053 return DV_E_DVASPECT;
4054 if (!psizel)
4055 return E_POINTER;
4056
4057 if (!isWidget || !qt.widget) // nothing to do
4058 return S_OK;
4059
4060 QSize proposedSize(MAP_LOGHIM_TO_PIX(psizel->cx, qt.widget->logicalDpiX()),
4061 MAP_LOGHIM_TO_PIX(psizel->cy, qt.widget->logicalDpiY()));
4062
4063 // can the widget be resized at all?
4064 if (qt.widget->minimumSize() == qt.widget->maximumSize() && qt.widget->minimumSize() != proposedSize)
4065 return E_FAIL;
4066 //Save the extent, bound to the widget restrictions.
4067 m_currentExtent.rwidth() = qBound(qt.widget->minimumWidth(), proposedSize.width(), qt.widget->maximumWidth());
4068 m_currentExtent.rheight() = qBound(qt.widget->minimumHeight(), proposedSize.height(), qt.widget->maximumHeight());
4069
4070 resize(proposedSize);
4071 return S_OK;
4072}
4073
4074/*
4075 Not implemented.
4076*/
4077HRESULT WINAPI QAxServerBase::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
4078{
4079 return S_OK;
4080}
4081
4082/*
4083 Not implemented.
4084*/
4085HRESULT WINAPI QAxServerBase::SetMoniker(DWORD, IMoniker*)
4086{
4087 return E_NOTIMPL;
4088}
4089
4090/*
4091 Disconnects an advise sink.
4092*/
4093HRESULT WINAPI QAxServerBase::Unadvise(DWORD dwConnection)
4094{
4095 for (int i = 0; i < adviseSinks.count(); ++i) {
4096 STATDATA entry = adviseSinks.at(i);
4097 if (entry.dwConnection == dwConnection) {
4098 entry.pAdvSink->Release();
4099 adviseSinks.removeAt(i);
4100 return S_OK;
4101 }
4102 }
4103 return OLE_E_NOCONNECTION;
4104}
4105
4106/*
4107 Not implemented.
4108*/
4109HRESULT WINAPI QAxServerBase::Update()
4110{
4111 return S_OK;
4112}
4113
4114//**** IDataObject
4115/*
4116 Calls IViewObject::Draw after setting up the parameters.
4117*/
4118HRESULT WINAPI QAxServerBase::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
4119{
4120 if (!pmedium)
4121 return E_POINTER;
4122 if ((pformatetcIn->tymed & TYMED_MFPICT) == 0)
4123 return DATA_E_FORMATETC;
4124
4125 internalCreate();
4126 if (!isWidget || !qt.widget)
4127 return E_UNEXPECTED;
4128
4129 // Container wants to draw, but the size is not defined yet - ask container
4130 if (m_spInPlaceSite && !qt.widget->testAttribute(Qt::WA_Resized)) {
4131 IOleInPlaceUIWindow *spInPlaceUIWindow = 0;
4132 RECT rcPos, rcClip;
4133 OLEINPLACEFRAMEINFO frameInfo;
4134 frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
4135
4136 HRESULT hres = m_spInPlaceSite->GetWindowContext(&m_spInPlaceFrame, &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo);
4137 if (hres == S_OK) {
4138 QSize size(rcPos.right - rcPos.left, rcPos.bottom - rcPos.top);
4139 resize(size);
4140 } else {
4141 qt.widget->adjustSize();
4142 }
4143 if (spInPlaceUIWindow) spInPlaceUIWindow->Release(); // no need for it
4144 }
4145
4146 int width = qt.widget->width();
4147 int height = qt.widget->height();
4148 RECTL rectl = {0, 0, width, height};
4149
4150 HDC hdc = CreateMetaFile(0);
4151 SaveDC(hdc);
4152 SetWindowOrgEx(hdc, 0, 0, 0);
4153 SetWindowExtEx(hdc, rectl.right, rectl.bottom, 0);
4154
4155 Draw(pformatetcIn->dwAspect, pformatetcIn->lindex, 0, pformatetcIn->ptd, 0, hdc, &rectl, &rectl, 0, 0);
4156
4157 RestoreDC(hdc, -1);
4158 HMETAFILE hMF = CloseMetaFile(hdc);
4159 if (!hMF)
4160 return E_UNEXPECTED;
4161
4162 HGLOBAL hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT));
4163 if (!hMem) {
4164 DeleteMetaFile(hMF);
4165 return ResultFromScode(STG_E_MEDIUMFULL);
4166 }
4167
4168 LPMETAFILEPICT pMF = (LPMETAFILEPICT)GlobalLock(hMem);
4169 pMF->hMF = hMF;
4170 pMF->mm = MM_ANISOTROPIC;
4171 pMF->xExt = MAP_PIX_TO_LOGHIM(width, qt.widget->logicalDpiX());
4172 pMF->yExt = MAP_PIX_TO_LOGHIM(height, qt.widget->logicalDpiY());
4173 GlobalUnlock(hMem);
4174
4175 memset(pmedium, 0, sizeof(STGMEDIUM));
4176 pmedium->tymed = TYMED_MFPICT;
4177 pmedium->hGlobal = hMem;
4178 pmedium->pUnkForRelease = 0;
4179
4180 return S_OK;
4181}
4182
4183/*
4184 Not implemented.
4185*/
4186HRESULT WINAPI QAxServerBase::DAdvise(FORMATETC *pformatetc, DWORD advf,
4187 IAdviseSink *pAdvSink, DWORD *pdwConnection)
4188{
4189 if (pformatetc->dwAspect != DVASPECT_CONTENT)
4190 return E_FAIL;
4191
4192 *pdwConnection = adviseSinks.count() + 1;
4193 STATDATA data = {
4194 {pformatetc->cfFormat,pformatetc->ptd,pformatetc->dwAspect,pformatetc->lindex,pformatetc->tymed},
4195 advf, pAdvSink, *pdwConnection
4196 };
4197 adviseSinks.append(data);
4198 pAdvSink->AddRef();
4199 return S_OK;
4200}
4201
4202/*
4203 Not implemented.
4204*/
4205HRESULT WINAPI QAxServerBase::DUnadvise(DWORD dwConnection)
4206{
4207 return Unadvise(dwConnection);
4208}
4209
4210/*
4211 Not implemented.
4212*/
4213HRESULT WINAPI QAxServerBase::EnumDAdvise(IEnumSTATDATA ** /*ppenumAdvise*/)
4214{
4215 return E_NOTIMPL;
4216}
4217
4218/*
4219 Not implemented.
4220*/
4221HRESULT WINAPI QAxServerBase::GetDataHere(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */)
4222{
4223 return E_NOTIMPL;
4224}
4225
4226/*
4227 Not implemented.
4228*/
4229HRESULT WINAPI QAxServerBase::QueryGetData(FORMATETC* /* pformatetc */)
4230{
4231 return E_NOTIMPL;
4232}
4233
4234/*
4235 Not implemented.
4236*/
4237HRESULT WINAPI QAxServerBase::GetCanonicalFormatEtc(FORMATETC* /* pformatectIn */,FORMATETC* /* pformatetcOut */)
4238{
4239 return E_NOTIMPL;
4240}
4241
4242/*
4243 Not implemented.
4244*/
4245HRESULT WINAPI QAxServerBase::SetData(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */, BOOL /* fRelease */)
4246{
4247 return E_NOTIMPL;
4248}
4249
4250/*
4251 Not implemented.
4252*/
4253HRESULT WINAPI QAxServerBase::EnumFormatEtc(DWORD /* dwDirection */, IEnumFORMATETC** /* ppenumFormatEtc */)
4254{
4255 return E_NOTIMPL;
4256}
4257
4258
4259
4260static int mapModifiers(int state)
4261{
4262 int ole = 0;
4263 if (state & Qt::ShiftModifier)
4264 ole |= 1;
4265 if (state & Qt::ControlModifier)
4266 ole |= 2;
4267 if (state & Qt::AltModifier)
4268 ole |= 4;
4269
4270 return ole;
4271}
4272
4273/*
4274 \reimp
4275*/
4276bool QAxServerBase::eventFilter(QObject *o, QEvent *e)
4277{
4278 if (!theObject)
4279 return QObject::eventFilter(o, e);
4280
4281 if ((e->type() == QEvent::Show || e->type() == QEvent::Hide) && (o == statusBar || o == menuBar)) {
4282 if (o == menuBar) {
4283 if (e->type() == QEvent::Hide) {
4284 createMenu(menuBar);
4285 } else if (e->type() == QEvent::Show) {
4286 removeMenu();
4287 }
4288 } else if (statusBar) {
4289 statusBar->setSizeGripEnabled(false);
4290 }
4291 updateGeometry();
4292 if (m_spInPlaceSite && qt.widget->sizeHint().isValid()) {
4293 RECT rect = {0, 0, qt.widget->sizeHint().width(), qt.widget->sizeHint().height()};
4294 m_spInPlaceSite->OnPosRectChange(&rect);
4295 }
4296 }
4297 switch (e->type()) {
4298 case QEvent::ChildAdded:
4299 static_cast<QChildEvent*>(e)->child()->installEventFilter(this);
4300 break;
4301 case QEvent::ChildRemoved:
4302 static_cast<QChildEvent*>(e)->child()->removeEventFilter(this);
4303 break;
4304 case QEvent::KeyPress:
4305 if (o == qt.object && hasStockEvents) {
4306 QKeyEvent *ke = (QKeyEvent*)e;
4307 int key = ke->key();
4308 int state = ke->modifiers();
4309 void *argv[] = {
4310 0,
4311 &key,
4312 &state
4313 };
4314 qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_KEYDOWN, argv);
4315 if (!ke->text().isEmpty())
4316 qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_KEYPRESS, argv);
4317 }
4318 break;
4319 case QEvent::KeyRelease:
4320 if (o == qt.object && hasStockEvents) {
4321 QKeyEvent *ke = (QKeyEvent*)e;
4322 int key = ke->key();
4323 int state = ke->modifiers();
4324 void *argv[] = {
4325 0,
4326 &key,
4327 &state
4328 };
4329 qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_KEYUP, argv);
4330 }
4331 break;
4332 case QEvent::MouseMove:
4333 if (o == qt.object && hasStockEvents) {
4334 QMouseEvent *me = (QMouseEvent*)e;
4335 int button = me->buttons() & Qt::MouseButtonMask;
4336 int state = mapModifiers(me->modifiers());
4337 int x = me->x();
4338 int y = me->y();
4339 void *argv[] = {
4340 0,
4341 &button,
4342 &state,
4343 &x,
4344 &y
4345 };
4346 qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_MOUSEMOVE, argv);
4347 }
4348 break;
4349 case QEvent::MouseButtonRelease:
4350 if (o == qt.object && hasStockEvents) {
4351 QMouseEvent *me = (QMouseEvent*)e;
4352 int button = me->button();
4353 int state = mapModifiers(me->modifiers());
4354 int x = me->x();
4355 int y = me->y();
4356 void *argv[] = {
4357 0,
4358 &button,
4359 &state,
4360 &x,
4361 &y
4362 };
4363 qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_MOUSEUP, argv);
4364 qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_CLICK, 0);
4365 }
4366 break;
4367 case QEvent::MouseButtonDblClick:
4368 if (o == qt.object && hasStockEvents) {
4369 qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_DBLCLICK, 0);
4370 }
4371 break;
4372 case QEvent::MouseButtonPress:
4373 if (m_spInPlaceSite && !isUIActive) {
4374 internalActivate();
4375 }
4376 if (o == qt.widget && hasStockEvents) {
4377 QMouseEvent *me = (QMouseEvent*)e;
4378 int button = me->button();
4379 int state = mapModifiers(me->modifiers());
4380 int x = me->x();
4381 int y = me->y();
4382 void *argv[] = {
4383 0,
4384 &button,
4385 &state,
4386 &x,
4387 &y
4388 };
4389 qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_MOUSEDOWN, argv);
4390 }
4391 break;
4392 case QEvent::Show:
4393 if (m_hWnd && o == qt.widget)
4394 ShowWindow(m_hWnd, SW_SHOW);
4395 updateMask();
4396 break;
4397 case QEvent::Hide:
4398 if (m_hWnd && o == qt.widget)
4399 ShowWindow(m_hWnd, SW_HIDE);
4400 break;
4401
4402 case QEvent::EnabledChange:
4403 if (m_hWnd && o == qt.widget)
4404 EnableWindow(m_hWnd, qt.widget->isEnabled());
4405 // Fall Through
4406 case QEvent::FontChange:
4407 case QEvent::ActivationChange:
4408 case QEvent::StyleChange:
4409 case QEvent::IconTextChange:
4410 case QEvent::ModifiedChange:
4411 case QEvent::Resize:
4412 updateMask();
4413 break;
4414 case QEvent::WindowBlocked: {
4415 if (!m_spInPlaceFrame)
4416 break;
4417 m_spInPlaceFrame->EnableModeless(FALSE);
4418 MSG msg;
4419 // Visual Basic 6.0 posts the message WM_USER+3078 from the EnableModeless().
4420 // While handling this message, VB will disable all current top-levels. After
4421 // this we have to re-enable the Qt modal widget to receive input events.
4422 if (PeekMessage(&msg, 0, WM_USER+3078, WM_USER+3078, PM_REMOVE)) {
4423 TranslateMessage(&msg);
4424 DispatchMessage(&msg);
4425 QWidget *modalWidget = QApplication::activeModalWidget();
4426 if (modalWidget && modalWidget->isVisible() && modalWidget->isEnabled()
4427 && !IsWindowEnabled(modalWidget->effectiveWinId()))
4428 EnableWindow(modalWidget->effectiveWinId(), TRUE);
4429 }
4430 break;
4431 }
4432 case QEvent::WindowUnblocked:
4433 if (!m_spInPlaceFrame)
4434 break;
4435 m_spInPlaceFrame->EnableModeless(TRUE);
4436 break;
4437 default:
4438 break;
4439 }
4440 return QObject::eventFilter(o, e);
4441}
4442
4443QT_END_NAMESPACE
4444#endif // QT_NO_WIN_ACTIVEQT
Note: See TracBrowser for help on using the repository browser.