Intégrer un exe externe dans l'interface (Windows) - Qt

Préface 

Je ne l'ai fait que auparavant. Pour appeler le programme externe exe dans l'interface, démarrez simplement QProcess. Maintenant, j'essaie d'intégrer un exe externe dans l'interface Qt, et c'est essentiellement implémenté. C'est assez magique !

rendus

J'ai écrit une petite démo, qui se déclenche via la barre de menu

Instructions et code

L'idée générale de mise en œuvre est la suivante : démarrez le programme externe à embarquer, puis obtenez le handle HWND de l'interface principale, convertissez-le en QWidget, et ajoutez-le à l'interface pour l'afficher.

Démarrer un programme externe

Démarrer un programme externe est assez simple. Il peut être implémenté à l'aide du QProcess de Qt, ou il peut être implémenté à l'aide de la méthode API Windows. Enregistrez-le ici, sinon vous l'oublierez (Remarque : la mise en veille est nécessaire, car si l'opération suivante est effectuée Immédiatement , Comme le processus n'est pas encore complètement terminé, le handle du formulaire ne peut pas être obtenu ):

//Qt 
qint64 MainWindow::startProcess(QString cmd)
{
    QProcess* process=new QProcess(this);
    process->setProgram(cmd);
    process->setCreateProcessArgumentsModifier([](QProcess::CreateProcessArguments *args)
    {
    args->startupInfo->wShowWindow = SW_HIDE;
    args->startupInfo->dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    }
    );
    process->start();
    Sleep(500);
    return process->processId();
}

//--------------------------------------------------------------------------

// Windows API
qint64 MainWindow::startProcess(QString cmd)
{
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_HIDE;

    bool bRet = CreateProcess(
        NULL,
        (LPWSTR)cmd.toStdWString().c_str(),
        NULL,
        NULL,
        FALSE,
		CREATE_NEW_CONSOLE,
        NULL,
        NULL, &si, &pi);

    Sleep(500);
    return (qint64)pi.dwProcessId;

}

Obtenez le handle du formulaire principal

Il est relativement simple de démarrer un programme externe. Il suffit d'utiliser le processus QProcess pour le démarrer et l'exécuter. Comment récupérer le handle de l'interface principale ? Après avoir vérifié les informations, il existe deux manières :

Méthode 1 : Obtenez le handle via FindWindow de l'API Windows  , mais vous devez connaître le nom de la classe d'interface principale et le nom du titre de l'exe externe. S'il s'agit d'un programme auto-développé, ces deux propriétés sont faciles à connaître, mais sinon , vous pouvez utiliser l'outil spy++ pour l'obtenir. . (ps : HWND est le même que WId, juste nommé différemment)

WId winId=(WId)FindWindow(L"无标题 - 记事本",L"Notepad");

Méthode 2 : Obtenez le handle du formulaire via EnumWindows de l’API Windows :

  • Obtenez les descripteurs de formulaire de tous les processus en cours via EnumWindows ;
  • Utilisez l'ID de processus spécifié pour filtrer le handle de formulaire de ce processus et l'enregistrer dans le conteneur ;
  • Pour connaître le handle du formulaire principal, demandez si la classe parent du handle du formulaire est vide. Si c'est le cas, il s'agit du handle du formulaire principal.

Le code spécifique est le suivant

typedef struct EnumHWndsArg
{
	std::vector<HWND>* vecHWnds;
	DWORD dwProcessId;
}EnumHWndsArg, *LPEnumHWndsArg;


BOOL CALLBACK lpEnumFunc(HWND hwnd, LPARAM lParam)
{
	EnumHWndsArg* pArg = (LPEnumHWndsArg)lParam;
	DWORD  processId;
	GetWindowThreadProcessId(hwnd, &processId);
	if (processId == pArg->dwProcessId)
	{
		pArg->vecHWnds->push_back(hwnd);
	}
	return TRUE;
}

void GetHWndsByProcessID(DWORD processID, std::vector<HWND>& vecHWnds)
{
	EnumHWndsArg wi;
	wi.dwProcessId = processID;
	wi.vecHWnds = &vecHWnds;
	EnumWindows(lpEnumFunc, (LPARAM)&wi);
}


WId MainWindow::getProcessWid(qint64 pid)
{
    if (pid != 0)
    {
        std::vector<HWND> vecHWnds;
        GetHWndsByProcessID((DWORD)pid, vecHWnds);
        for (const HWND& h : vecHWnds)
        {
            HWND parent = GetParent(h);
            if (parent == NULL)
            {
                return (WId)h;
            }
        }
    }
    return 0;
}

Ajouter à l'interface 

void MainWindow::addTabOfWindow(WId wid, QString tabName,QString path)
{
    if(wid==0)
        return;

    QWindow *pWindow = QWindow::fromWinId(wid);

    pWindow->setFlags(pWindow->flags()|Qt::CustomizeWindowHint |Qt::WindowTitleHint );
    QWidget *pWidget = QWidget::createWindowContainer(pWindow);
    pWidget->setProperty("path",path);
    ui->tabWidget->addTab(pWidget, tabName);
}

Remarque : L'interface Qt que j'ai écrite et les applications fournies avec Windows (Bloc-notes, etc.) sont toutes deux acceptables. Cependant, j'ai essayé plusieurs applications couramment utilisées telles que NetEase Cloud, WeChat, etc., mais elles ne peuvent pas être intégrées dans le interface.Pendant le processus, bien que le handle soit obtenu (la valeur n'est pas vide), le programme externe apparaît toujours lorsqu'il est affiché. Il se peut que la couche sous-jacente ne soit pas écrite dans le format Windows standard, la conversion ne pouvant donc pas aboutir.

Code source

https://download.csdn.net/download/xiaopei_yan/88214817

Conclusion

J'ai l'impression que cette tentative a été très enrichissante !

Je suppose que tu aimes

Origine blog.csdn.net/xiaopei_yan/article/details/125931178
conseillé
Classement