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

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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