解决非qt程序不能调用qt dll的问题
This commit is contained in:
parent
2e41e33a44
commit
146f0a1b7d
|
@ -1,6 +1,6 @@
|
||||||
QT += core gui
|
QT += core gui
|
||||||
|
|
||||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets gui-private
|
||||||
|
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
|
|
||||||
|
@ -42,9 +42,18 @@ if (contains(DEFINES, OEM_HANWANG) || contains(DEFINES, OEM_LISICHENG) || contai
|
||||||
}
|
}
|
||||||
|
|
||||||
win32 {
|
win32 {
|
||||||
|
SOURCES += ../../../modules/saneui/dllmain.cpp
|
||||||
|
SOURCES += ../../../modules/saneui/qmfcapp.cpp
|
||||||
|
SOURCES += ../../../modules/saneui/qwinhost.cpp
|
||||||
|
SOURCES += ../../../modules/saneui/qwinwidget.cpp
|
||||||
|
|
||||||
|
HEADERS += ../../../modules/saneui/qmfcapp.h
|
||||||
|
HEADERS += ../../../modules/saneui/qwinhost.h
|
||||||
|
HEADERS += ../../../modules/saneui/qwinwidget.h
|
||||||
|
|
||||||
DEF_FILE = HGSaneUI.def
|
DEF_FILE = HGSaneUI.def
|
||||||
DEFINES += _CRT_SECURE_NO_WARNINGS
|
DEFINES += _CRT_SECURE_NO_WARNINGS
|
||||||
LIBS += -ladvapi32
|
LIBS += -ladvapi32 -luser32
|
||||||
|
|
||||||
if (contains(DEFINES, OEM_HANWANG) || contains(DEFINES, OEM_LISICHENG) || contains(DEFINES, OEM_CANGTIAN) || contains(DEFINES, OEM_ZHONGJING) || contains(DEFINES, OEM_ZIGUANG)) {
|
if (contains(DEFINES, OEM_HANWANG) || contains(DEFINES, OEM_LISICHENG) || contains(DEFINES, OEM_CANGTIAN) || contains(DEFINES, OEM_ZHONGJING) || contains(DEFINES, OEM_ZIGUANG)) {
|
||||||
contains(DEFINES, OEM_HANWANG) {
|
contains(DEFINES, OEM_HANWANG) {
|
||||||
|
|
|
@ -2,4 +2,7 @@ TEMPLATE = subdirs
|
||||||
|
|
||||||
SUBDIRS += \
|
SUBDIRS += \
|
||||||
HGSaneUI \
|
HGSaneUI \
|
||||||
HGDemo
|
HGDemo
|
||||||
|
|
||||||
|
HGDemo.depends = \
|
||||||
|
HGSaneUI
|
|
@ -1,28 +1,26 @@
|
||||||
#include "HGSaneUI.h"
|
#include "HGSaneUI.h"
|
||||||
#include "dialog_device_select.h"
|
#include "dialog_device_select.h"
|
||||||
#include "dialog_device_scan.h"
|
#include "dialog_device_scan.h"
|
||||||
#include <QApplication>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#ifdef HG_CMP_MSC
|
||||||
|
#include "qwinwidget.h"
|
||||||
|
extern HINSTANCE g_hInst;
|
||||||
|
extern bool g_ownApplication;
|
||||||
|
#endif
|
||||||
|
|
||||||
int show_devlist_ui(SANEAPI* saneApi, HGWindow parent, SANE_Handle *handle, char *devName, unsigned int maxLen)
|
int show_devlist_ui(SANEAPI* saneApi, HGWindow parent, SANE_Handle *handle, char *devName, unsigned int maxLen)
|
||||||
{
|
{
|
||||||
if (nullptr == saneApi || nullptr == handle)
|
if (nullptr == saneApi || nullptr == handle)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (nullptr == qApp)
|
|
||||||
{
|
|
||||||
#ifdef HG_CMP_MSC
|
|
||||||
// 创建WIN32窗口
|
|
||||||
return -2;
|
|
||||||
#else
|
|
||||||
return -2;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
QWidget *qParent = nullptr;
|
QWidget *qParent = nullptr;
|
||||||
#ifdef HG_CMP_MSC
|
#ifdef HG_CMP_MSC
|
||||||
qParent = QWidget::find((WId)parent);
|
if (!g_ownApplication)
|
||||||
if (nullptr != parent && nullptr == qParent)
|
g_ownApplication = QMfcApp::pluginInstance(g_hInst);
|
||||||
return -2;
|
QWinWidget win(parent);
|
||||||
|
win.showCentered();
|
||||||
|
qParent = &win;
|
||||||
#else
|
#else
|
||||||
qParent = parent;
|
qParent = parent;
|
||||||
#endif
|
#endif
|
||||||
|
@ -49,16 +47,6 @@ int show_setting_ui(SANEAPI* saneApi, SANE_Handle handle, HGWindow parent)
|
||||||
if (nullptr == saneApi || nullptr == handle)
|
if (nullptr == saneApi || nullptr == handle)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (nullptr == qApp)
|
|
||||||
{
|
|
||||||
#ifdef HG_CMP_MSC
|
|
||||||
// 创建WIN32窗口
|
|
||||||
return -2;
|
|
||||||
#else
|
|
||||||
return -2;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,21 +55,13 @@ int show_scan_ui(SANEAPI* saneApi, SANE_Handle handle, HGWindow parent, show_sca
|
||||||
if (nullptr == saneApi || nullptr == handle)
|
if (nullptr == saneApi || nullptr == handle)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (nullptr == qApp)
|
|
||||||
{
|
|
||||||
#ifdef HG_CMP_MSC
|
|
||||||
// 创建WIN32窗口
|
|
||||||
return -2;
|
|
||||||
#else
|
|
||||||
return -2;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
QWidget *qParent = nullptr;
|
QWidget *qParent = nullptr;
|
||||||
#ifdef HG_CMP_MSC
|
#ifdef HG_CMP_MSC
|
||||||
qParent = QWidget::find((WId)parent);
|
if (!g_ownApplication)
|
||||||
if (nullptr != parent && nullptr == qParent)
|
g_ownApplication = QMfcApp::pluginInstance(g_hInst);
|
||||||
return -2;
|
QWinWidget win(parent);
|
||||||
|
win.showCentered();
|
||||||
|
qParent = &win;
|
||||||
#else
|
#else
|
||||||
qParent = parent;
|
qParent = parent;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include "qmfcapp.h"
|
||||||
|
#include "qwinwidget.h"
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
HINSTANCE g_hInst = NULL;
|
||||||
|
bool g_ownApplication = FALSE;
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpvReserved*/)
|
||||||
|
{
|
||||||
|
if (dwReason == DLL_PROCESS_ATTACH)
|
||||||
|
{
|
||||||
|
g_hInst = hInstance;
|
||||||
|
}
|
||||||
|
else if (dwReason == DLL_PROCESS_DETACH)
|
||||||
|
{
|
||||||
|
if (g_ownApplication)
|
||||||
|
delete qApp;
|
||||||
|
g_hInst = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
|
@ -0,0 +1,427 @@
|
||||||
|
// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
// Implementation of the QMfcApp classes
|
||||||
|
|
||||||
|
#ifdef QT3_SUPPORT
|
||||||
|
#undef QT3_SUPPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef UNICODE
|
||||||
|
#undef UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "qmfcapp.h"
|
||||||
|
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QAbstractEventDispatcher>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#ifdef QTWINMIGRATE_WITHMFC
|
||||||
|
#include <afxwin.h>
|
||||||
|
#else
|
||||||
|
#include <qt_windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef QTWINMIGRATE_WITHMFC
|
||||||
|
CWinApp *QMfcApp::mfc_app = 0;
|
||||||
|
char **QMfcApp::mfc_argv = 0;
|
||||||
|
int QMfcApp::mfc_argc = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
#define QT_WA(unicode, ansi) unicode
|
||||||
|
|
||||||
|
QMfcAppEventFilter::QMfcAppEventFilter() : QAbstractNativeEventFilter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QMfcAppEventFilter::nativeEventFilter(const QByteArray &, void *message, long *result)
|
||||||
|
{
|
||||||
|
return static_cast<QMfcApp*>(qApp)->winEventFilter((MSG*)message, result);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! \class QMfcApp qmfcapp.h
|
||||||
|
\brief The QMfcApp class provides merging of the MFC and Qt event loops.
|
||||||
|
|
||||||
|
QMfcApp is responsible for driving both the Qt and MFC event loop.
|
||||||
|
It replaces the standard MFC event loop provided by
|
||||||
|
CWinApp::Run(), and is used instead of the QApplication parent
|
||||||
|
class.
|
||||||
|
|
||||||
|
To replace the MFC event loop reimplement the CWinApp::Run()
|
||||||
|
function in the CWinApp subclass usually created by the MFC
|
||||||
|
Application Wizard, and use either the static run() function, or
|
||||||
|
an instance of QMfcApp created earlier through the static
|
||||||
|
instance() function or the constructor.
|
||||||
|
|
||||||
|
The QMfcApp class also provides a static API pluginInstance() that
|
||||||
|
drives the Qt event loop when loaded into an MFC or Win32 application.
|
||||||
|
This is useful for developing Qt based DLLs or plugins, or if the
|
||||||
|
MFC application's event handling can not be modified.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int modalLoopCount = 0;
|
||||||
|
|
||||||
|
HHOOK hhook;
|
||||||
|
LRESULT CALLBACK QtFilterProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (qApp) {
|
||||||
|
// don't process deferred-deletes while in a modal loop
|
||||||
|
if (modalLoopCount)
|
||||||
|
qApp->sendPostedEvents();
|
||||||
|
else
|
||||||
|
qApp->sendPostedEvents(0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallNextHookEx(hhook, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Inform Qt that a modal loop is about to be entered, and that DeferredDelete
|
||||||
|
events should not be processed. Call this function before calling Win32
|
||||||
|
or MFC functions that enter a modal event loop (i.e. MessageBox).
|
||||||
|
|
||||||
|
This is only required if the Qt UI code hooks into an existing Win32
|
||||||
|
event loop using QMfcApp::pluginInstance.
|
||||||
|
|
||||||
|
\sa exitModalLoop()
|
||||||
|
*/
|
||||||
|
void QMfcApp::enterModalLoop()
|
||||||
|
{
|
||||||
|
++modalLoopCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Inform Qt that a modal loop has been exited, and that DeferredDelete
|
||||||
|
events should not be processed. Call this function after the blocking
|
||||||
|
Win32 or MFC function (i.e. MessageBox) returned.
|
||||||
|
|
||||||
|
This is only required if the Qt UI code hooks into an existing Win32
|
||||||
|
event loop using QMfcApp::pluginInstance.
|
||||||
|
|
||||||
|
\sa enterModalLoop()
|
||||||
|
*/
|
||||||
|
void QMfcApp::exitModalLoop()
|
||||||
|
{
|
||||||
|
--modalLoopCount;
|
||||||
|
Q_ASSERT(modalLoopCount >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
If there is no global QApplication object (i.e. qApp is null) this
|
||||||
|
function creates a QApplication instance and returns true;
|
||||||
|
otherwise it does nothing and returns false.
|
||||||
|
|
||||||
|
The application installs an event filter that drives the Qt event
|
||||||
|
loop while the MFC or Win32 application continues to own the event
|
||||||
|
loop.
|
||||||
|
|
||||||
|
Use this static function if the application event loop code can not be
|
||||||
|
easily modified, or when developing a plugin or DLL that will be loaded
|
||||||
|
into an existing Win32 or MFC application. If \a plugin is non-null then
|
||||||
|
the function loads the respective DLL explicitly to avoid unloading from
|
||||||
|
memory.
|
||||||
|
|
||||||
|
\code
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved)
|
||||||
|
{
|
||||||
|
if (dwReason == DLL_PROCESS_ATTACH)
|
||||||
|
QMfcApp::pluginInstance(hInstance);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Set \a plugin to 0 when calling this function from within the same executable
|
||||||
|
module.
|
||||||
|
|
||||||
|
If this function is used, call enterModalLoop and exitModalLoop whenever you
|
||||||
|
call a Win32 or MFC function that opens a local event loop.
|
||||||
|
|
||||||
|
\code
|
||||||
|
void Dialog::someSlot()
|
||||||
|
{
|
||||||
|
QMfcApp::enterModalLoop();
|
||||||
|
MessageBox(...);
|
||||||
|
QMfcApp::exitModalLoop();
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
bool QMfcApp::pluginInstance(Qt::HANDLE plugin)
|
||||||
|
{
|
||||||
|
if (qApp)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
QT_WA({
|
||||||
|
hhook = SetWindowsHookExW(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId());
|
||||||
|
}, {
|
||||||
|
hhook = SetWindowsHookExA(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId());
|
||||||
|
});
|
||||||
|
|
||||||
|
int argc = 0;
|
||||||
|
(void)new QApplication(argc, 0);
|
||||||
|
|
||||||
|
if (plugin) {
|
||||||
|
char filename[256];
|
||||||
|
if (GetModuleFileNameA((HINSTANCE)plugin, filename, 255))
|
||||||
|
LoadLibraryA(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
Q_GLOBAL_STATIC(QMfcAppEventFilter, qmfcEventFilter);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef QTWINMIGRATE_WITHMFC
|
||||||
|
/*!
|
||||||
|
Runs the event loop for both Qt and the MFC application object \a
|
||||||
|
mfcApp, and returns the result. This function calls \c instance()
|
||||||
|
if no QApplication object exists and deletes the object it
|
||||||
|
created.
|
||||||
|
|
||||||
|
Calling this static function in a reimplementation of
|
||||||
|
CWinApp::Run() is the simpliest way to use the QMfcApp class:
|
||||||
|
|
||||||
|
\code
|
||||||
|
int MyMfcApp::Run()
|
||||||
|
{
|
||||||
|
return QMfcApp::run(this);
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Since a QApplication object must exist before Qt widgets can be
|
||||||
|
created you cannot use this function if you want to use Qt-based
|
||||||
|
user interface elements in, for example, the InitInstance()
|
||||||
|
function of CWinApp. In such cases, create an instance of
|
||||||
|
QApplication explicitly using instance() or the constructor.
|
||||||
|
|
||||||
|
\sa instance()
|
||||||
|
*/
|
||||||
|
int QMfcApp::run(CWinApp *mfcApp)
|
||||||
|
{
|
||||||
|
bool ownInstance = !qApp;
|
||||||
|
if (ownInstance)
|
||||||
|
instance(mfcApp);
|
||||||
|
int result = qApp->exec();
|
||||||
|
|
||||||
|
if (mfcApp) {
|
||||||
|
int mfcRes = mfcApp->ExitInstance();
|
||||||
|
if (mfcRes && !result)
|
||||||
|
result = mfcRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ownInstance)
|
||||||
|
delete qApp;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates an instance of QApplication, passing the command line of
|
||||||
|
\a mfcApp to the QApplication constructor, and returns the new
|
||||||
|
object. The returned object must be destroyed by the caller.
|
||||||
|
|
||||||
|
Use this static function if you want to perform additional
|
||||||
|
initializations after creating the application object, or if you
|
||||||
|
want to create Qt GUI elements in the InitInstance()
|
||||||
|
reimplementation of CWinApp:
|
||||||
|
|
||||||
|
\code
|
||||||
|
BOOL MyMfcApp::InitInstance()
|
||||||
|
{
|
||||||
|
// standard MFC initialization
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// This sets the global qApp pointer
|
||||||
|
QMfcApp::instance(this);
|
||||||
|
|
||||||
|
// Qt GUI initialization
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL MyMfcApp::Run()
|
||||||
|
{
|
||||||
|
int result = QMfcApp::run(this);
|
||||||
|
delete qApp;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\sa run()
|
||||||
|
*/
|
||||||
|
QApplication *QMfcApp::instance(CWinApp *mfcApp)
|
||||||
|
{
|
||||||
|
mfc_app = mfcApp;
|
||||||
|
if (mfc_app) {
|
||||||
|
#if defined(UNICODE)
|
||||||
|
QString exeName((QChar*)mfc_app->m_pszExeName, wcslen(mfc_app->m_pszExeName));
|
||||||
|
QString cmdLine((QChar*)mfc_app->m_lpCmdLine, wcslen(mfc_app->m_lpCmdLine));
|
||||||
|
#else
|
||||||
|
QString exeName = QString::fromLocal8Bit(mfc_app->m_pszExeName);
|
||||||
|
QString cmdLine = QString::fromLocal8Bit(mfc_app->m_lpCmdLine);
|
||||||
|
#endif
|
||||||
|
QStringList arglist = QString(exeName + " " + cmdLine).split(' ');
|
||||||
|
|
||||||
|
mfc_argc = arglist.count();
|
||||||
|
mfc_argv = new char*[mfc_argc+1];
|
||||||
|
int a;
|
||||||
|
for (a = 0; a < mfc_argc; ++a) {
|
||||||
|
QString arg = arglist[a];
|
||||||
|
mfc_argv[a] = new char[arg.length()+1];
|
||||||
|
qstrcpy(mfc_argv[a], arg.toLocal8Bit().data());
|
||||||
|
}
|
||||||
|
mfc_argv[a] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new QMfcApp(mfcApp, mfc_argc, mfc_argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool qmfc_eventFilter(void *message)
|
||||||
|
{
|
||||||
|
long result = 0;
|
||||||
|
return static_cast<QMfcApp*>(qApp)->winEventFilter((MSG*)message, &result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates an instance of QMfcApp. \a mfcApp must point to the
|
||||||
|
existing instance of CWinApp. \a argc and \a argv are passed on
|
||||||
|
to the QApplication constructor.
|
||||||
|
|
||||||
|
Use the static function instance() to automatically use the
|
||||||
|
command line passed to the CWinApp.
|
||||||
|
|
||||||
|
\code
|
||||||
|
QMfcApp *qtApp;
|
||||||
|
|
||||||
|
BOOL MyMfcApp::InitInstance()
|
||||||
|
{
|
||||||
|
// standard MFC initialization
|
||||||
|
|
||||||
|
int argc = ...
|
||||||
|
char **argv = ...
|
||||||
|
|
||||||
|
qtApp = new QMfcApp(this, argc, argv);
|
||||||
|
|
||||||
|
// Qt GUI initialization
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL MyMfcApp::Run()
|
||||||
|
{
|
||||||
|
int result = qtApp->exec();
|
||||||
|
delete qtApp;
|
||||||
|
qtApp = 0;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\sa instance() run()
|
||||||
|
*/
|
||||||
|
QMfcApp::QMfcApp(CWinApp *mfcApp, int &argc, char **argv)
|
||||||
|
: QApplication(argc, argv), idleCount(0), doIdle(FALSE)
|
||||||
|
{
|
||||||
|
mfc_app = mfcApp;
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
QAbstractEventDispatcher::instance()->installNativeEventFilter(qmfcEventFilter());
|
||||||
|
#else
|
||||||
|
QAbstractEventDispatcher::instance()->setEventFilter(qmfc_eventFilter);
|
||||||
|
#endif
|
||||||
|
setQuitOnLastWindowClosed(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QMfcApp::QMfcApp(int &argc, char **argv) : QApplication(argc, argv)
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
QAbstractEventDispatcher::instance()->installNativeEventFilter(qmfcEventFilter());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
Destroys the QMfcApp object, freeing all allocated resources.
|
||||||
|
*/
|
||||||
|
QMfcApp::~QMfcApp()
|
||||||
|
{
|
||||||
|
if (hhook) {
|
||||||
|
UnhookWindowsHookEx(hhook);
|
||||||
|
hhook = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef QTWINMIGRATE_WITHMFC
|
||||||
|
for (int a = 0; a < mfc_argc; ++a) {
|
||||||
|
char *arg = mfc_argv[a];
|
||||||
|
delete[] arg;
|
||||||
|
}
|
||||||
|
delete []mfc_argv;
|
||||||
|
|
||||||
|
mfc_argc = 0;
|
||||||
|
mfc_argv = 0;
|
||||||
|
mfc_app = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\reimp
|
||||||
|
*/
|
||||||
|
bool QMfcApp::winEventFilter(MSG *msg, long *result)
|
||||||
|
{
|
||||||
|
static bool recursion = false;
|
||||||
|
if (recursion)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
recursion = true;
|
||||||
|
|
||||||
|
QWidget *widget = QWidget::find((WId)msg->hwnd);
|
||||||
|
HWND toplevel = 0;
|
||||||
|
if (widget) {
|
||||||
|
HWND parent = (HWND)widget->winId();
|
||||||
|
while(parent) {
|
||||||
|
toplevel = parent;
|
||||||
|
parent = GetParent(parent);
|
||||||
|
}
|
||||||
|
HMENU menu = toplevel ? GetMenu(toplevel) : 0;
|
||||||
|
if (menu && GetFocus() == msg->hwnd) {
|
||||||
|
if (msg->message == WM_SYSKEYUP && msg->wParam == VK_MENU) {
|
||||||
|
// activate menubar on Alt-up and move focus away
|
||||||
|
SetFocus(toplevel);
|
||||||
|
SendMessage(toplevel, msg->message, msg->wParam, msg->lParam);
|
||||||
|
widget->setFocus();
|
||||||
|
recursion = false;
|
||||||
|
return TRUE;
|
||||||
|
} else if (msg->message == WM_SYSKEYDOWN && msg->wParam != VK_MENU) {
|
||||||
|
SendMessage(toplevel, msg->message, msg->wParam, msg->lParam);
|
||||||
|
SendMessage(toplevel, WM_SYSKEYUP, VK_MENU, msg->lParam);
|
||||||
|
recursion = false;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef QTWINMIGRATE_WITHMFC
|
||||||
|
else if (mfc_app) {
|
||||||
|
MSG tmp;
|
||||||
|
while (doIdle && !PeekMessage(&tmp, 0, 0, 0, PM_NOREMOVE)) {
|
||||||
|
if (!mfc_app->OnIdle(idleCount++))
|
||||||
|
doIdle = FALSE;
|
||||||
|
}
|
||||||
|
if (mfc_app->IsIdleMessage(msg)) {
|
||||||
|
doIdle = TRUE;
|
||||||
|
idleCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mfc_app && mfc_app->PreTranslateMessage(msg)) {
|
||||||
|
recursion = false;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
recursion = false;
|
||||||
|
#if QT_VERSION < 0x050000
|
||||||
|
return QApplication::winEventFilter(msg, result);
|
||||||
|
#else
|
||||||
|
Q_UNUSED(result);
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
|
||||||
|
// Declaration of the QMfcApp classes
|
||||||
|
|
||||||
|
#ifndef QMFCAPP_H
|
||||||
|
#define QMFCAPP_H
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
#if defined(_AFXDLL) && defined(_MSC_VER)
|
||||||
|
#define QTWINMIGRATE_WITHMFC
|
||||||
|
class CWinApp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
#include <QAbstractNativeEventFilter>
|
||||||
|
|
||||||
|
class QMfcAppEventFilter : public QAbstractNativeEventFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QMfcAppEventFilter();
|
||||||
|
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class QMfcApp : public QApplication
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool pluginInstance(Qt::HANDLE plugin = 0);
|
||||||
|
|
||||||
|
#ifdef QTWINMIGRATE_WITHMFC
|
||||||
|
static int run(CWinApp *mfcApp);
|
||||||
|
static QApplication *instance(CWinApp *mfcApp);
|
||||||
|
QMfcApp(CWinApp *mfcApp, int &argc, char **argv);
|
||||||
|
#endif
|
||||||
|
QMfcApp(int &argc, char **argv);
|
||||||
|
~QMfcApp();
|
||||||
|
|
||||||
|
bool winEventFilter(MSG *msg, long *result);
|
||||||
|
|
||||||
|
static void enterModalLoop();
|
||||||
|
static void exitModalLoop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef QTWINMIGRATE_WITHMFC
|
||||||
|
static char ** mfc_argv;
|
||||||
|
static int mfc_argc;
|
||||||
|
static CWinApp *mfc_app;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int idleCount;
|
||||||
|
bool doIdle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QMFCAPP_H
|
|
@ -0,0 +1,325 @@
|
||||||
|
// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
// Implementation of the QWinHost classes
|
||||||
|
|
||||||
|
#ifdef QT3_SUPPORT
|
||||||
|
#undef QT3_SUPPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "qwinhost.h"
|
||||||
|
|
||||||
|
#include <QEvent>
|
||||||
|
#include <qt_windows.h>
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
#define QT_WA(unicode, ansi) unicode
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class QWinHost qwinhost.h
|
||||||
|
\brief The QWinHost class provides an API to use native Win32
|
||||||
|
windows in Qt applications.
|
||||||
|
|
||||||
|
QWinHost exists to provide a QWidget that can act as a parent for
|
||||||
|
any native Win32 control. Since QWinHost is a proper QWidget, it
|
||||||
|
can be used as a toplevel widget (e.g. 0 parent) or as a child of
|
||||||
|
any other QWidget.
|
||||||
|
|
||||||
|
QWinHost integrates the native control into the Qt user interface,
|
||||||
|
e.g. handles focus switches and laying out.
|
||||||
|
|
||||||
|
Applications moving to Qt may have custom Win32 controls that will
|
||||||
|
take time to rewrite with Qt. Such applications can use these
|
||||||
|
custom controls as children of QWinHost widgets. This allows the
|
||||||
|
application's user interface to be replaced gradually.
|
||||||
|
|
||||||
|
When the QWinHost is destroyed, and the Win32 window hasn't been
|
||||||
|
set with setWindow(), the window will also be destroyed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates an instance of QWinHost. \a parent and \a f are
|
||||||
|
passed on to the QWidget constructor. The widget has by default
|
||||||
|
no background.
|
||||||
|
|
||||||
|
\warning You cannot change the parent widget of the QWinHost instance
|
||||||
|
after the native window has been created, i.e. do not call
|
||||||
|
QWidget::setParent or move the QWinHost into a different layout.
|
||||||
|
*/
|
||||||
|
QWinHost::QWinHost(QWidget *parent, Qt::WindowFlags f)
|
||||||
|
: QWidget(parent, f), wndproc(0),own_hwnd(false), hwnd(0)
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_NoBackground);
|
||||||
|
setAttribute(Qt::WA_NoSystemBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Destroys the QWinHost object. If the hosted Win32 window has not
|
||||||
|
been set explicitly using setWindow() the window will be
|
||||||
|
destroyed.
|
||||||
|
*/
|
||||||
|
QWinHost::~QWinHost()
|
||||||
|
{
|
||||||
|
if (wndproc) {
|
||||||
|
#if defined(GWLP_WNDPROC)
|
||||||
|
QT_WA({
|
||||||
|
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc);
|
||||||
|
},{
|
||||||
|
SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc);
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
QT_WA({
|
||||||
|
SetWindowLong(hwnd, GWL_WNDPROC, (LONG)wndproc);
|
||||||
|
},{
|
||||||
|
SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)wndproc);
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwnd && own_hwnd)
|
||||||
|
DestroyWindow(hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Reimplement this virtual function to create and return the native
|
||||||
|
Win32 window. \a parent is the handle to this widget, and \a
|
||||||
|
instance is the handle to the application instance. The returned HWND
|
||||||
|
must be a child of the \a parent HWND.
|
||||||
|
|
||||||
|
The default implementation returns null. The window returned by a
|
||||||
|
reimplementation of this function is owned by this QWinHost
|
||||||
|
instance and will be destroyed in the destructor.
|
||||||
|
|
||||||
|
This function is called by the implementation of polish() if no
|
||||||
|
window has been set explicitly using setWindow(). Call polish() to
|
||||||
|
force this function to be called.
|
||||||
|
|
||||||
|
\sa setWindow()
|
||||||
|
*/
|
||||||
|
HWND QWinHost::createWindow(HWND parent, HINSTANCE instance)
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent);
|
||||||
|
Q_UNUSED(instance);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Ensures that the window provided a child of this widget, unless
|
||||||
|
it is a WS_OVERLAPPED window.
|
||||||
|
*/
|
||||||
|
void QWinHost::fixParent()
|
||||||
|
{
|
||||||
|
if (!hwnd)
|
||||||
|
return;
|
||||||
|
if (!::IsWindow(hwnd)) {
|
||||||
|
hwnd = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (::GetParent(hwnd) == (HWND)winId())
|
||||||
|
return;
|
||||||
|
long style = GetWindowLong(hwnd, GWL_STYLE);
|
||||||
|
if (style & WS_OVERLAPPED)
|
||||||
|
return;
|
||||||
|
::SetParent(hwnd, (HWND)winId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the native Win32 window to \a window. If \a window is not a child
|
||||||
|
window of this widget, then it is reparented to become one. If \a window
|
||||||
|
is not a child window (i.e. WS_OVERLAPPED is set), then this function does nothing.
|
||||||
|
|
||||||
|
The lifetime of the window handle will be managed by Windows, QWinHost does not
|
||||||
|
call DestroyWindow. To verify that the handle is destroyed when expected, handle
|
||||||
|
WM_DESTROY in the window procedure.
|
||||||
|
|
||||||
|
\sa window(), createWindow()
|
||||||
|
*/
|
||||||
|
void QWinHost::setWindow(HWND window)
|
||||||
|
{
|
||||||
|
if (hwnd && own_hwnd)
|
||||||
|
DestroyWindow(hwnd);
|
||||||
|
|
||||||
|
hwnd = window;
|
||||||
|
fixParent();
|
||||||
|
|
||||||
|
own_hwnd = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the handle to the native Win32 window, or null if no
|
||||||
|
window has been set or created yet.
|
||||||
|
|
||||||
|
\sa setWindow(), createWindow()
|
||||||
|
*/
|
||||||
|
HWND QWinHost::window() const
|
||||||
|
{
|
||||||
|
return hwnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *getWindowProc(QWinHost *host)
|
||||||
|
{
|
||||||
|
return host ? host->wndproc : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK WinHostProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
QWinHost *widget = qobject_cast<QWinHost*>(QWidget::find((WId)::GetParent(hwnd)));
|
||||||
|
WNDPROC oldproc = (WNDPROC)getWindowProc(widget);
|
||||||
|
if (widget) {
|
||||||
|
switch(msg) {
|
||||||
|
case WM_LBUTTONDOWN:
|
||||||
|
if (::GetFocus() != hwnd && (widget->focusPolicy() & Qt::ClickFocus)) {
|
||||||
|
widget->setFocus(Qt::MouseFocusReason);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_SYSKEYDOWN:
|
||||||
|
case WM_SYSKEYUP:
|
||||||
|
QT_WA({
|
||||||
|
SendMessage((HWND)widget->winId(), msg, wParam, lParam);
|
||||||
|
}, {
|
||||||
|
SendMessageA((HWND)widget->winId(), msg, wParam, lParam);
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
if (wParam == VK_TAB) {
|
||||||
|
QT_WA({
|
||||||
|
SendMessage((HWND)widget->winId(), msg, wParam, lParam);
|
||||||
|
}, {
|
||||||
|
SendMessageA((HWND)widget->winId(), msg, wParam, lParam);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QT_WA({
|
||||||
|
if (oldproc)
|
||||||
|
return CallWindowProc(oldproc, hwnd, msg, wParam, lParam);
|
||||||
|
return DefWindowProc(hwnd,msg,wParam,lParam);
|
||||||
|
}, {
|
||||||
|
if (oldproc)
|
||||||
|
return CallWindowProcA(oldproc, hwnd, msg, wParam, lParam);
|
||||||
|
return DefWindowProcA(hwnd,msg,wParam,lParam);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\reimp
|
||||||
|
*/
|
||||||
|
bool QWinHost::event(QEvent *e)
|
||||||
|
{
|
||||||
|
switch(e->type()) {
|
||||||
|
case QEvent::Polish:
|
||||||
|
if (!hwnd) {
|
||||||
|
hwnd = createWindow(HWND(winId()), GetModuleHandle(0));
|
||||||
|
fixParent();
|
||||||
|
own_hwnd = hwnd != 0;
|
||||||
|
}
|
||||||
|
if (hwnd && !wndproc && GetParent(hwnd) == (HWND)winId()) {
|
||||||
|
#if defined(GWLP_WNDPROC)
|
||||||
|
QT_WA({
|
||||||
|
wndproc = (void*)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
|
||||||
|
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WinHostProc);
|
||||||
|
}, {
|
||||||
|
wndproc = (void*)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
|
||||||
|
SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)WinHostProc);
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
QT_WA({
|
||||||
|
wndproc = (void*)GetWindowLong(hwnd, GWL_WNDPROC);
|
||||||
|
SetWindowLong(hwnd, GWL_WNDPROC, (LONG)WinHostProc);
|
||||||
|
}, {
|
||||||
|
wndproc = (void*)GetWindowLongA(hwnd, GWL_WNDPROC);
|
||||||
|
SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)WinHostProc);
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LONG style;
|
||||||
|
QT_WA({
|
||||||
|
style = GetWindowLong(hwnd, GWL_STYLE);
|
||||||
|
}, {
|
||||||
|
style = GetWindowLongA(hwnd, GWL_STYLE);
|
||||||
|
})
|
||||||
|
if (style & WS_TABSTOP)
|
||||||
|
setFocusPolicy(Qt::FocusPolicy(focusPolicy() | Qt::StrongFocus));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QEvent::WindowBlocked:
|
||||||
|
if (hwnd)
|
||||||
|
EnableWindow(hwnd, false);
|
||||||
|
break;
|
||||||
|
case QEvent::WindowUnblocked:
|
||||||
|
if (hwnd)
|
||||||
|
EnableWindow(hwnd, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return QWidget::event(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\reimp
|
||||||
|
*/
|
||||||
|
void QWinHost::showEvent(QShowEvent *e)
|
||||||
|
{
|
||||||
|
QWidget::showEvent(e);
|
||||||
|
|
||||||
|
if (hwnd)
|
||||||
|
SetWindowPos(hwnd, HWND_TOP, 0, 0, width(), height(), SWP_SHOWWINDOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\reimp
|
||||||
|
*/
|
||||||
|
void QWinHost::focusInEvent(QFocusEvent *e)
|
||||||
|
{
|
||||||
|
QWidget::focusInEvent(e);
|
||||||
|
|
||||||
|
if (hwnd)
|
||||||
|
::SetFocus(hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\reimp
|
||||||
|
*/
|
||||||
|
void QWinHost::resizeEvent(QResizeEvent *e)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(e);
|
||||||
|
|
||||||
|
if (hwnd)
|
||||||
|
SetWindowPos(hwnd, HWND_TOP, 0, 0, width(), height(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\reimp
|
||||||
|
*/
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
bool QWinHost::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||||
|
#else
|
||||||
|
bool QWinHost::winEvent(MSG *msg, long *result)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
MSG *msg = (MSG *)message;
|
||||||
|
#endif
|
||||||
|
switch (msg->message)
|
||||||
|
{
|
||||||
|
case WM_SETFOCUS:
|
||||||
|
if (hwnd) {
|
||||||
|
::SetFocus(hwnd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
return QWidget::nativeEvent(eventType, message, result);
|
||||||
|
#else
|
||||||
|
return QWidget::winEvent(msg, result);
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
|
||||||
|
// Declaration of the QWinHost classes
|
||||||
|
|
||||||
|
#ifndef QWINHOST_H
|
||||||
|
#define QWINHOST_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class QWinHost : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
QWinHost(QWidget *parent = 0, Qt::WindowFlags f = 0);
|
||||||
|
~QWinHost();
|
||||||
|
|
||||||
|
void setWindow(HWND);
|
||||||
|
HWND window() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual HWND createWindow(HWND parent, HINSTANCE instance);
|
||||||
|
|
||||||
|
bool event(QEvent *e);
|
||||||
|
void showEvent(QShowEvent *);
|
||||||
|
void focusInEvent(QFocusEvent*);
|
||||||
|
void resizeEvent(QResizeEvent*);
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
|
||||||
|
#else
|
||||||
|
bool winEvent(MSG *msg, long *result);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
void fixParent();
|
||||||
|
friend void* getWindowProc(QWinHost*);
|
||||||
|
|
||||||
|
void *wndproc;
|
||||||
|
bool own_hwnd;
|
||||||
|
HWND hwnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QWINHOST_H
|
|
@ -0,0 +1,359 @@
|
||||||
|
// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
// Implementation of the QWinWidget classes
|
||||||
|
|
||||||
|
#ifdef QT3_SUPPORT
|
||||||
|
#undef QT3_SUPPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef UNICODE
|
||||||
|
#undef UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "qmfcapp.h"
|
||||||
|
|
||||||
|
#ifdef QTWINMIGRATE_WITHMFC
|
||||||
|
#include <afxwin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <qevent.h>
|
||||||
|
|
||||||
|
#include "qwinwidget.h"
|
||||||
|
|
||||||
|
#include <qt_windows.h>
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
#include <QWindow>
|
||||||
|
#include <qpa/qplatformnativeinterface.h>
|
||||||
|
#define QT_WA(unicode, ansi) unicode
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class QWinWidget qwinwidget.h
|
||||||
|
\brief The QWinWidget class is a Qt widget that can be child of a
|
||||||
|
native Win32 widget.
|
||||||
|
|
||||||
|
The QWinWidget class is the bridge between an existing application
|
||||||
|
user interface developed using native Win32 APIs or toolkits like
|
||||||
|
MFC, and Qt based GUI elements.
|
||||||
|
|
||||||
|
Using QWinWidget as the parent of QDialogs will ensure that
|
||||||
|
modality, placement and stacking works properly throughout the
|
||||||
|
entire application. If the child widget is a top level window that
|
||||||
|
uses the \c WDestructiveClose flag, QWinWidget will destroy itself
|
||||||
|
when the child window closes down.
|
||||||
|
|
||||||
|
Applications moving to Qt can use QWinWidget to add new
|
||||||
|
functionality, and gradually replace the existing interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates an instance of QWinWidget. \a hParentWnd is the handle to
|
||||||
|
the native Win32 parent. If a \a parent is provided the object is
|
||||||
|
owned by that QObject. \a f is passed on to the QWidget constructor.
|
||||||
|
*/
|
||||||
|
QWinWidget::QWinWidget(HWND hParentWnd, QObject *parent, Qt::WindowFlags f)
|
||||||
|
: QWidget(0, f), hParent(hParentWnd), prevFocus(0), reenable_parent(false)
|
||||||
|
{
|
||||||
|
if (parent)
|
||||||
|
QObject::setParent(parent);
|
||||||
|
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef QTWINMIGRATE_WITHMFC
|
||||||
|
/*!
|
||||||
|
\overload
|
||||||
|
|
||||||
|
Creates an instance of QWinWidget. \a parentWnd is a pointer to an
|
||||||
|
MFC window object. If a \a parent is provided the object is owned
|
||||||
|
by that QObject. \a f is passed on to the QWidget constructor.
|
||||||
|
*/
|
||||||
|
QWinWidget::QWinWidget(CWnd *parentWnd, QObject *parent, Qt::WindowFlags f)
|
||||||
|
: QWidget(0, f), hParent(parentWnd ? parentWnd->m_hWnd : 0), prevFocus(0), reenable_parent(false)
|
||||||
|
{
|
||||||
|
if (parent)
|
||||||
|
QObject::setParent(parent);
|
||||||
|
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void QWinWidget::init()
|
||||||
|
{
|
||||||
|
Q_ASSERT(hParent);
|
||||||
|
|
||||||
|
if (hParent) {
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
setProperty("_q_embedded_native_parent_handle", WId(hParent));
|
||||||
|
#endif
|
||||||
|
// make the widget window style be WS_CHILD so SetParent will work
|
||||||
|
QT_WA({
|
||||||
|
SetWindowLong((HWND)winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
|
||||||
|
}, {
|
||||||
|
SetWindowLongA((HWND)winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
|
||||||
|
})
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
QWindow *window = windowHandle();
|
||||||
|
HWND h = static_cast<HWND>(QGuiApplication::platformNativeInterface()->
|
||||||
|
nativeResourceForWindow("handle", window));
|
||||||
|
SetParent(h, hParent);
|
||||||
|
window->setFlags(Qt::FramelessWindowHint);
|
||||||
|
#else
|
||||||
|
SetParent(winId(), hParent);
|
||||||
|
#endif
|
||||||
|
QEvent e(QEvent::EmbeddingControl);
|
||||||
|
QApplication::sendEvent(this, &e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Destroys this object, freeing all allocated resources.
|
||||||
|
*/
|
||||||
|
QWinWidget::~QWinWidget()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the handle of the native Win32 parent window.
|
||||||
|
*/
|
||||||
|
HWND QWinWidget::parentWindow() const
|
||||||
|
{
|
||||||
|
return hParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\reimp
|
||||||
|
*/
|
||||||
|
void QWinWidget::childEvent(QChildEvent *e)
|
||||||
|
{
|
||||||
|
QObject *obj = e->child();
|
||||||
|
if (obj->isWidgetType()) {
|
||||||
|
if (e->added()) {
|
||||||
|
if (obj->isWidgetType()) {
|
||||||
|
obj->installEventFilter(this);
|
||||||
|
}
|
||||||
|
} else if (e->removed() && reenable_parent) {
|
||||||
|
reenable_parent = false;
|
||||||
|
EnableWindow(hParent, true);
|
||||||
|
obj->removeEventFilter(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QWidget::childEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \internal */
|
||||||
|
void QWinWidget::saveFocus()
|
||||||
|
{
|
||||||
|
if (!prevFocus)
|
||||||
|
prevFocus = ::GetFocus();
|
||||||
|
if (!prevFocus)
|
||||||
|
prevFocus = parentWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Shows this widget. Overrides QWidget::show().
|
||||||
|
|
||||||
|
\sa showCentered()
|
||||||
|
*/
|
||||||
|
void QWinWidget::show()
|
||||||
|
{
|
||||||
|
saveFocus();
|
||||||
|
QWidget::show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Centers this widget over the native parent window. Use this
|
||||||
|
function to have Qt toplevel windows (i.e. dialogs) positioned
|
||||||
|
correctly over their native parent windows.
|
||||||
|
|
||||||
|
\code
|
||||||
|
QWinWidget qwin(hParent);
|
||||||
|
qwin.center();
|
||||||
|
|
||||||
|
QMessageBox::information(&qwin, "Caption", "Information Text");
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
This will center the message box over the client area of hParent.
|
||||||
|
*/
|
||||||
|
void QWinWidget::center()
|
||||||
|
{
|
||||||
|
const QWidget *child = findChild<QWidget*>();
|
||||||
|
if (child && !child->isWindow()) {
|
||||||
|
qWarning("QWinWidget::center: Call this function only for QWinWidgets with toplevel children");
|
||||||
|
}
|
||||||
|
RECT r;
|
||||||
|
GetWindowRect(hParent, &r);
|
||||||
|
setGeometry((r.right-r.left)/2+r.left, (r.bottom-r.top)/2+r.top,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\obsolete
|
||||||
|
|
||||||
|
Call center() instead.
|
||||||
|
*/
|
||||||
|
void QWinWidget::showCentered()
|
||||||
|
{
|
||||||
|
center();
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the focus to the window that had the focus before this widget
|
||||||
|
was shown, or if there was no previous window, sets the focus to
|
||||||
|
the parent window.
|
||||||
|
*/
|
||||||
|
void QWinWidget::resetFocus()
|
||||||
|
{
|
||||||
|
if (prevFocus)
|
||||||
|
::SetFocus(prevFocus);
|
||||||
|
else
|
||||||
|
::SetFocus(parentWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \reimp
|
||||||
|
*/
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
bool QWinWidget::nativeEvent(const QByteArray &, void *message, long *)
|
||||||
|
#else
|
||||||
|
bool QWinWidget::winEvent(MSG *msg, long *)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
MSG *msg = (MSG *)message;
|
||||||
|
#endif
|
||||||
|
if (msg->message == WM_SETFOCUS) {
|
||||||
|
Qt::FocusReason reason;
|
||||||
|
if (::GetKeyState(VK_LBUTTON) < 0 || ::GetKeyState(VK_RBUTTON) < 0)
|
||||||
|
reason = Qt::MouseFocusReason;
|
||||||
|
else if (::GetKeyState(VK_SHIFT) < 0)
|
||||||
|
reason = Qt::BacktabFocusReason;
|
||||||
|
else
|
||||||
|
reason = Qt::TabFocusReason;
|
||||||
|
QFocusEvent e(QEvent::FocusIn, reason);
|
||||||
|
QApplication::sendEvent(this, &e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\reimp
|
||||||
|
*/
|
||||||
|
bool QWinWidget::eventFilter(QObject *o, QEvent *e)
|
||||||
|
{
|
||||||
|
QWidget *w = (QWidget*)o;
|
||||||
|
|
||||||
|
switch (e->type()) {
|
||||||
|
case QEvent::WindowDeactivate:
|
||||||
|
if (w->isModal() && w->isHidden())
|
||||||
|
BringWindowToTop(hParent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QEvent::Hide:
|
||||||
|
if (reenable_parent) {
|
||||||
|
EnableWindow(hParent, true);
|
||||||
|
reenable_parent = false;
|
||||||
|
}
|
||||||
|
resetFocus();
|
||||||
|
if (w->testAttribute(Qt::WA_DeleteOnClose) && w->isWindow())
|
||||||
|
deleteLater();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QEvent::Show:
|
||||||
|
if (w->isWindow()) {
|
||||||
|
saveFocus();
|
||||||
|
hide();
|
||||||
|
if (w->isModal() && !reenable_parent) {
|
||||||
|
EnableWindow(hParent, false);
|
||||||
|
reenable_parent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QEvent::Close:
|
||||||
|
::SetActiveWindow(hParent);
|
||||||
|
if (w->testAttribute(Qt::WA_DeleteOnClose))
|
||||||
|
deleteLater();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QWidget::eventFilter(o, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \reimp
|
||||||
|
*/
|
||||||
|
void QWinWidget::focusInEvent(QFocusEvent *e)
|
||||||
|
{
|
||||||
|
QWidget *candidate = this;
|
||||||
|
|
||||||
|
switch (e->reason()) {
|
||||||
|
case Qt::TabFocusReason:
|
||||||
|
case Qt::BacktabFocusReason:
|
||||||
|
while (!(candidate->focusPolicy() & Qt::TabFocus)) {
|
||||||
|
candidate = candidate->nextInFocusChain();
|
||||||
|
if (candidate == this) {
|
||||||
|
candidate = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (candidate) {
|
||||||
|
candidate->setFocus(e->reason());
|
||||||
|
if (e->reason() == Qt::BacktabFocusReason || e->reason() == Qt::TabFocusReason) {
|
||||||
|
candidate->setAttribute(Qt::WA_KeyboardFocusChange);
|
||||||
|
candidate->window()->setAttribute(Qt::WA_KeyboardFocusChange);
|
||||||
|
}
|
||||||
|
if (e->reason() == Qt::BacktabFocusReason)
|
||||||
|
QWidget::focusNextPrevChild(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \reimp
|
||||||
|
*/
|
||||||
|
bool QWinWidget::focusNextPrevChild(bool next)
|
||||||
|
{
|
||||||
|
QWidget *curFocus = focusWidget();
|
||||||
|
if (!next) {
|
||||||
|
if (!curFocus->isWindow()) {
|
||||||
|
QWidget *nextFocus = curFocus->nextInFocusChain();
|
||||||
|
QWidget *prevFocus = 0;
|
||||||
|
QWidget *topLevel = 0;
|
||||||
|
while (nextFocus != curFocus) {
|
||||||
|
if (nextFocus->focusPolicy() & Qt::TabFocus) {
|
||||||
|
prevFocus = nextFocus;
|
||||||
|
topLevel = 0;
|
||||||
|
} else if (nextFocus->isWindow()) {
|
||||||
|
topLevel = nextFocus;
|
||||||
|
}
|
||||||
|
nextFocus = nextFocus->nextInFocusChain();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!topLevel) {
|
||||||
|
return QWidget::focusNextPrevChild(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QWidget *nextFocus = curFocus;
|
||||||
|
while (1) {
|
||||||
|
nextFocus = nextFocus->nextInFocusChain();
|
||||||
|
if (nextFocus->isWindow())
|
||||||
|
break;
|
||||||
|
if (nextFocus->focusPolicy() & Qt::TabFocus) {
|
||||||
|
return QWidget::focusNextPrevChild(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::SetFocus(hParent);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
|
||||||
|
// Declaration of the QWinWidget classes
|
||||||
|
|
||||||
|
#ifndef QWINWIDGET_H
|
||||||
|
#define QWINWIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include "qmfcapp.h"
|
||||||
|
|
||||||
|
class CWnd;
|
||||||
|
|
||||||
|
class QWinWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
QWinWidget( HWND hParentWnd, QObject *parent = 0, Qt::WindowFlags f = 0 );
|
||||||
|
#ifdef QTWINMIGRATE_WITHMFC
|
||||||
|
QWinWidget( CWnd *parnetWnd, QObject *parent = 0, Qt::WindowFlags f = 0 );
|
||||||
|
#endif
|
||||||
|
~QWinWidget();
|
||||||
|
|
||||||
|
void show();
|
||||||
|
void center();
|
||||||
|
void showCentered();
|
||||||
|
|
||||||
|
HWND parentWindow() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void childEvent( QChildEvent *e );
|
||||||
|
bool eventFilter( QObject *o, QEvent *e );
|
||||||
|
|
||||||
|
bool focusNextPrevChild(bool next);
|
||||||
|
void focusInEvent(QFocusEvent *e);
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
|
||||||
|
#else
|
||||||
|
bool winEvent(MSG *msg, long *result);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init();
|
||||||
|
|
||||||
|
void saveFocus();
|
||||||
|
void resetFocus();
|
||||||
|
|
||||||
|
HWND hParent;
|
||||||
|
HWND prevFocus;
|
||||||
|
bool reenable_parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QWINWIDGET_H
|
Loading…
Reference in New Issue