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

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

trunk: Merged in qt 4.6.2 sources.

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