blob: 43ec8cdbab81952f856b931a6e9d321afa11622b [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the ActiveQt framework of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qstringlist.h>
#include <qvector.h>
#include "qaxfactory.h"
#ifndef QT_NO_WIN_ACTIVEQT
#include <qt_windows.h>
QT_BEGIN_NAMESPACE
static DWORD *classRegistration = 0;
static DWORD dwThreadID;
static bool qAxActivity = false;
static HANDLE hEventShutdown;
#ifdef QT_DEBUG
QT_STATIC_CONST DWORD dwTimeOut = 1000;
QT_STATIC_CONST DWORD dwPause = 500;
#else
QT_STATIC_CONST DWORD dwTimeOut = 5000; // time for EXE to be idle before shutting down
QT_STATIC_CONST DWORD dwPause = 1000; // time to wait for threads to finish up
#endif
extern HANDLE hEventShutdown;
extern bool qAxActivity;
extern HANDLE qAxInstance;
extern bool qAxIsServer;
extern bool qAxOutProcServer;
extern wchar_t qAxModuleFilename[MAX_PATH];
extern QString qAxInit();
extern void qAxCleanup();
extern HRESULT UpdateRegistry(BOOL bRegister);
extern HRESULT GetClassObject(const GUID &clsid, const GUID &iid, void **ppUnk);
extern ulong qAxLockCount();
extern bool qax_winEventFilter(void *message);
#if defined(Q_CC_BOR)
extern "C" __stdcall HRESULT DumpIDL(const QString &outfile, const QString &ver);
#else
STDAPI DumpIDL(const QString &outfile, const QString &ver);
#endif
// Monitors the shutdown event
static DWORD WINAPI MonitorProc(void* pv)
{
while (1) {
WaitForSingleObject(hEventShutdown, INFINITE);
DWORD dwWait=0;
do {
qAxActivity = false;
dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut);
} while (dwWait == WAIT_OBJECT_0);
// timed out
if (!qAxActivity && !qAxLockCount()) // if no activity let's really bail
break;
}
CloseHandle(hEventShutdown);
PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
PostQuitMessage(0);
return 0;
}
// Starts the monitoring thread
static bool StartMonitor()
{
dwThreadID = GetCurrentThreadId();
hEventShutdown = CreateEvent(0, false, false, 0);
if (hEventShutdown == 0)
return false;
DWORD dwThreadID;
HANDLE h = CreateThread(0, 0, MonitorProc, 0, 0, &dwThreadID);
return (h != NULL);
}
void qax_shutDown()
{
qAxActivity = true;
if (hEventShutdown)
SetEvent(hEventShutdown); // tell monitor that we transitioned to zero
}
/*
Start the COM server (if necessary).
*/
bool qax_startServer(QAxFactory::ServerType type)
{
if (qAxIsServer)
return true;
const QStringList keys = qAxFactory()->featureList();
if (!keys.count())
return false;
if (!qAxFactory()->isService())
StartMonitor();
classRegistration = new DWORD[keys.count()];
int object = 0;
for (QStringList::ConstIterator key = keys.begin(); key != keys.end(); ++key, ++object) {
IUnknown* p = 0;
CLSID clsid = qAxFactory()->classID(*key);
// Create a QClassFactory (implemented in qaxserverbase.cpp)
HRESULT hRes = GetClassObject(clsid, IID_IClassFactory, (void**)&p);
if (SUCCEEDED(hRes))
hRes = CoRegisterClassObject(clsid, p, CLSCTX_LOCAL_SERVER,
type == QAxFactory::MultipleInstances ? REGCLS_MULTIPLEUSE : REGCLS_SINGLEUSE,
classRegistration+object);
if (p)
p->Release();
}
qAxIsServer = true;
return true;
}
/*
Stop the COM server (if necessary).
*/
bool qax_stopServer()
{
if (!qAxIsServer || !classRegistration)
return true;
qAxIsServer = false;
const QStringList keys = qAxFactory()->featureList();
int object = 0;
for (QStringList::ConstIterator key = keys.begin(); key != keys.end(); ++key, ++object)
CoRevokeClassObject(classRegistration[object]);
delete []classRegistration;
classRegistration = 0;
Sleep(dwPause); //wait for any threads to finish
return true;
}
#if defined(Q_OS_WINCE)
extern void __cdecl qWinMain(HINSTANCE, HINSTANCE, LPSTR, int, int &, QVector<char *> &);
#else
extern void qWinMain(HINSTANCE, HINSTANCE, LPSTR, int, int &, QVector<char *> &);
#endif
QT_END_NAMESPACE
#if defined(QT_NEEDS_QMAIN)
int qMain(int, char **);
#define main qMain
#else
#if defined(Q_OS_WINCE)
extern "C" int __cdecl main(int, char **);
#else
extern "C" int main(int, char **);
#endif
#endif
EXTERN_C int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR, int nShowCmd)
{
QT_USE_NAMESPACE
qAxOutProcServer = true;
GetModuleFileName(0, qAxModuleFilename, MAX_PATH);
qAxInstance = hInstance;
QByteArray cmdParam = QString::fromWCharArray(GetCommandLine()).toLocal8Bit();
QList<QByteArray> cmds = cmdParam.split(' ');
QByteArray unprocessed;
int nRet = 0;
bool run = true;
bool runServer = false;
for (int i = 0; i < cmds.count(); ++i) {
QByteArray cmd = cmds.at(i).toLower();
if (cmd == "-activex" || cmd == "/activex" || cmd == "-embedding" || cmd == "/embedding") {
runServer = true;
} else if (cmd == "-unregserver" || cmd == "/unregserver") {
nRet = UpdateRegistry(false);
run = false;
break;
} else if (cmd == "-regserver" || cmd == "/regserver") {
nRet = UpdateRegistry(true);
run = false;
break;
} else if (cmd == "-dumpidl" || cmd == "/dumpidl") {
++i;
if (i < cmds.count()) {
QByteArray outfile = cmds.at(i);
++i;
QByteArray version;
if (i < cmds.count() && (cmds.at(i) == "-version" || cmds.at(i) == "/version")) {
++i;
if (i < cmds.count())
version = cmds.at(i);
else
version = "1.0";
}
nRet = DumpIDL(QString::fromLatin1(outfile.constData()), QString::fromLatin1(version.constData()));
} else {
qWarning("Wrong commandline syntax: <app> -dumpidl <idl file> [-version <x.y.z>]");
}
run = false;
break;
} else {
unprocessed += cmds.at(i) + ' ';
}
}
if (run) {
HRESULT hRes = CoInitialize(0);
int argc;
QVector<char*> argv(8);
qWinMain(hInstance, hPrevInstance, unprocessed.data(), nShowCmd, argc, argv);
qAxInit();
if (runServer)
QAxFactory::startServer();
nRet = ::main(argc, argv.data());
QAxFactory::stopServer();
qAxCleanup();
CoUninitialize();
}
return nRet;
}
#endif // QT_NO_WIN_ACTIVEQT