summaryrefslogtreecommitdiffstats
path: root/src/activeqt/control/qaxserverdll.cpp
blob: 38169db8caa9062a937412f3a7a67aa790b54978 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright (C) 2015 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

#include <qapplication.h>
#include <private/qcoreapplication_p.h>
#include <qwidget.h>
#include <qdir.h>

#include <qt_windows.h>

#include "qclassfactory_p.h"

QT_BEGIN_NAMESPACE

bool qax_ownQApp = false;
HHOOK qax_hhook = nullptr;

// in qaxserver.cpp
extern wchar_t qAxModuleFilename[MAX_PATH];
extern bool qAxIsServer;
extern ITypeLib *qAxTypeLibrary;
extern unsigned long qAxLockCount();
extern QString qAxInit();
extern void qAxCleanup();
extern HANDLE qAxInstance;
static uint qAxThreadId = 0;

extern HRESULT UpdateRegistry(bool bRegister, bool perUser);
extern HRESULT GetClassObject(const GUID &clsid, const GUID &iid, void **ppUnk);

STDAPI DllRegisterServer()
{
    return UpdateRegistry(true, false);
}

STDAPI DllUnregisterServer()
{
    return UpdateRegistry(false, false);
}

STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine) {
    bool perUser = false; // per-user (un)registration
    if (pszCmdLine) {
        if (QStringView(pszCmdLine).compare(u"user", Qt::CaseInsensitive) == 0)
            perUser = true;
    }

    if (bInstall) {
        HRESULT hr = UpdateRegistry(true, perUser);
        if (FAILED(hr))
            UpdateRegistry(false, perUser);
        return hr;
    } else {
        return UpdateRegistry(false, perUser);
    }
}

STDAPI DllGetClassObject(const GUID &clsid, const GUID &iid, void** ppv)
{
    if (!qAxThreadId)
        qAxThreadId = GetCurrentThreadId();
    else if (GetCurrentThreadId() != qAxThreadId)
        return E_FAIL;

    GetClassObject(clsid, iid, ppv);
    if (!*ppv)
        return CLASS_E_CLASSNOTAVAILABLE;
    return S_OK;
}

STDAPI DllCanUnloadNow()
{
    if (GetCurrentThreadId() != qAxThreadId)
        return S_FALSE;
    if (qAxLockCount())
        return S_FALSE;
    if (!qax_ownQApp)
        return S_OK;

    // check if qApp still runs widgets (in other DLLs)
    QWidgetList widgets = QApplication::allWidgets();
    qsizetype count = widgets.size();
    for (qsizetype w = 0; w < widgets.size(); ++w) {
        // remove all Qt generated widgets
        QWidget *widget = widgets.at(w);
        if (widget->windowType() == Qt::Desktop || widget->objectName() == QLatin1String("Qt internal tablet widget"))
            count--;
    }
    if (count)
        return S_FALSE;

    // no widgets left - destroy qApp
    if (qax_hhook)
        UnhookWindowsHookEx(qax_hhook);

    QClassFactory::cleanupCreatedApplication(*qApp);
    delete qApp;
    qax_ownQApp = false;

    // never allow unloading - safety net for Internet Explorer
    return S_FALSE;
}


EXTERN_C BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpvReserved */)
{
    GetModuleFileName(hInstance, qAxModuleFilename, MAX_PATH);
    // Point QApplication here such that the directory is added to the patch, and qt.conf and
    // deployed plugins are found.
    QCoreApplicationPrivate::setApplicationFilePath(QDir::cleanPath(QString::fromWCharArray(qAxModuleFilename)));

    qAxInstance = hInstance;
    qAxIsServer = true;

    if (dwReason == DLL_PROCESS_ATTACH) {
        DisableThreadLibraryCalls(hInstance);
        qAxInit();
    } else if (dwReason == DLL_PROCESS_DETACH) {
        qAxCleanup();
    }

    return true;
}

QT_END_NAMESPACE