MFC实现嵌入第三方exe程序到窗口中

MFC实现嵌入第三方exe程序到窗口中,显示StartProcess找不到标识符,如何改正;
参考一下链接
https://blog.csdn.net/m0_60352504/article/details/127062604

img

img

// MFCApplication1Dlg.cpp : 实现文件
//

#include "stdafx.h"
#include "MFCApplication1.h"
#include "MFCApplication1Dlg.h"
#include "afxdialogex.h"

#include   "resource.h"
#include    
#include   "windows.h"
#include
#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_ABOUTBOX };
#endif

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CMFCApplication1Dlg 对话框



CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BUTTON1, &CMFCApplication1Dlg::OnBnClickedButton1)
END_MESSAGE_MAP()


// CMFCApplication1Dlg 消息处理程序

BOOL CMFCApplication1Dlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO: 在此添加额外的初始化代码
    void InitStart();
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
void CMFCApplication1Dlg::InitStart()
{
    ///****************************************************/
    HANDLE handle = StartProcess(_T("C:\\Windows\\system32\\notepad.exe"), _T(""));
    Sleep(4000);//等待exe程序完全显示,酌情可删除
    UpdateData(TRUE);
    HWND m_hwnd = NULL;//.定义为全局
    CRect rc;
    //GetDlgItem(IDC_CRT)->GetClientRect(&rc);
    GetDlgItem(IDC_STATIC)->GetWindowRect(&rc);//IDC_ECGVIEW静态文本控件ID
                                                //m_EcgPic.GetWindowRect(&rc);
    int nWidth = rc.Width();
    int nHeight = rc.Height();
    ScreenToClient(rc);

    while (!m_hwnd)
    {
        //hwnd =::FindWindow("类名","窗口标题");
        m_hwnd = ::FindWindow(NULL, _T("Develop"));//Develop Configuration
    }
    if (m_hwnd)
    {
        LONG style = GetWindowLong(m_hwnd, GWL_STYLE);// 14CF 0000

        style &= ~WS_CAPTION;
        style &= ~WS_THICKFRAME;
        //style |=WS_CHILD;//*
        SetWindowLong(m_hwnd, GWL_STYLE, style);

        ::SetParent(m_hwnd, this->m_hWnd);
        ::MoveWindow(m_hwnd, rc.left + 10, rc.top + 10, nWidth - 20, nHeight - 20, true); //将外部程序移到自自身窗口里//*
        ::SetWindowPos(m_hwnd, HWND_TOP, rc.left + 10, rc.top + 10, nWidth - 20, nHeight - 20, SWP_SHOWWINDOW | SWP_HIDEWINDOW);
        // ::BringWindowToTop(m_hwnd);//*
        // Invalidate();//*
        //::UpdateWindow(m_hwnd);//*
        ::ShowWindow(m_hwnd, SW_SHOW);
    }
    /***************************************************************************/
}


void CMFCApplication1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CMFCApplication1Dlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplication1Dlg::OnQueryDragIcon()
{
    return static_cast(m_hIcon);
}



void CMFCApplication1Dlg::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知处理程序代码


}

//program程序路径 args程序参数
HANDLE StartProcess(LPCTSTR program, LPCTSTR args)
{

    HANDLE hProcess = NULL;
    PROCESS_INFORMATION processInfo;
    STARTUPINFO startupInfo;
    ::ZeroMemory(&startupInfo, sizeof(startupInfo));
    startupInfo.cb = sizeof(startupInfo);
    if (::CreateProcess(program, (LPTSTR)args,
        NULL,  // process security
        NULL,  // thread security
        FALSE, // no inheritance
        0,     // no startup flags
        NULL,  // no special environment
        NULL,  // default startup directory
        &startupInfo,
        &processInfo))
        return hProcess;
}

编译器是自上而下解析的,你在调用StartProcess函数时,这个函数的定义在调用处的下面,都还没解析,自然找不到.

在调用这个函数代码前面 加上 函数的声明
HANDLE StartProcess(LPCTSTR program, LPCTSTR args);

或者
你把函数的定义放到调用处的前面

等那个程序运行了,用findwindow找到handle
然后 setparent 即可
如果不要窗口边框,用 setwindowlong 去掉 captionbar 属性

在MFC应用程序中嵌入第三方EXE程序,可以使用MFC的CWnd类和Windows API的CreateProcess函数。在CreateProcess函数中,需要指定可执行文件的路径和命令行参数,以及启动进程的一些其他参数。然后,使用CWnd类的Create函数来创建一个窗口,并在窗口中嵌入刚刚创建的进程。

如果您遇到了“StartProcess找不到标识符”的错误,可能是因为您的代码中没有定义这个标识符。您需要确保在代码中正确地引用了该标识符。具体来说,StartProcess是一个函数或变量的名称,您需要在代码中定义这个函数或变量并初始化它,以便在程序运行时可以使用它。

以下是一个简单的示例代码,用于在MFC应用程序中嵌入Notepad程序:

// 定义命令行参数
LPCTSTR szCmdline = _T("notepad.exe");

// 启动进程
STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));

BOOL bSuccess = CreateProcess(NULL, (LPWSTR)szCmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if (!bSuccess)
{
    // 处理错误情况
    return;
}

// 创建窗口并嵌入进程
CWnd* pWnd = new CWnd();
pWnd->CreateEx(0, AfxRegisterWndClass(0), NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, AfxGetMainWnd()->GetSafeHwnd(), NULL, NULL);
::SetParent(pi.hProcess, pWnd->GetSafeHwnd());

请注意,此代码仅适用于Windows操作系统,并且仅用于演示目的。实际应用程序中,您需要根据自己的需求进行适当的修改和调整。

基于最新版ChatGPT4的回答,望采纳!!!有其他问题也可以询问我哦、”(最新版更智能,功能更加强大)

在MFC中嵌入第三方exe程序到窗口中,可以通过使用CreateProcessSetParent函数实现。首先创建一个新的进程来运行第三方exe程序,然后将该进程的主窗口嵌入到MFC应用程序的窗口中。

请注意,StartProcess不是一个标准的Windows API函数。如果你遇到找不到标识符的错误,可能是因为你使用了错误的函数名。你应该使用CreateProcess来启动新的进程。

以下是一个示例,演示如何在MFC应用程序中嵌入第三方exe程序:

#include <afxwin.h>
#include <iostream>

// 嵌入第三方exe程序到指定窗口
BOOL EmbedExternalApp(CWnd *pWndParent, const CString &strExePath)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    // 启动第三方exe程序
    if (!CreateProcess(strExePath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
    {
        std::cerr << "Failed to create process. Error code: " << GetLastError() << std::endl;
        return FALSE;
    }

    // 等待进程创建窗口
    Sleep(100);

    // 获取第三方程序的主窗口句柄
    HWND hWndExternalApp = ::FindWindow(NULL, _T("External App Window Title")); // 请将 External App Window Title 替换为第三方程序的窗口标题
    if (hWndExternalApp == NULL)
    {
        std::cerr << "Failed to find external app window. Error code: " << GetLastError() << std::endl;
        return FALSE;
    }

    // 将第三方程序的主窗口嵌入到MFC应用程序的窗口中
    ::SetParent(hWndExternalApp, pWndParent->m_hWnd);

    return TRUE;
}

你可以将此EmbedExternalApp函数添加到你的MFC应用程序中,并在适当的位置调用它。请确保提供正确的第三方exe程序路径和窗口标题。此外,根据需要,你可能需要调整Sleep函数的参数以确保进程有足够的时间创建窗口。

例如,你可以在CMainFrame类的OnCreate方法中调用此函数,将第三方exe程序嵌入到MFC应用程序的主窗口中:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;

    // 嵌入第三方exe程序
    EmbedExternalApp(this, _T("C:\\Path\\To\\Your\\ExternalApp.exe"));

    return 0;
}

这个示例仅作为引导,你可能需要根据你的应用程序需求进行相应的调整。

参考GPT和自己的思路:在您提供的代码中,InitStart() 函数的声明是错误的,因为它包含在 BOOL CMFCApplication1Dlg::OnInitDialog() 函数内部。解决这个问题,您可以在头文件中声明 InitStart() 函数,然后在 .cpp 文件中定义它。此外,代码中使用了一个未定义的函数 StartProcess(),因此您需要确保该函数被正确定义和包含。

以下是代码的修改建议:

1 在头文件中声明 InitStart() 函数:

class CMFCApplication1Dlg : public CDialogEx
{
public:
    CMFCApplication1Dlg(CWnd* pParent = nullptr);
    virtual ~CMFCApplication1Dlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_MFCAPPLICATION1_DIALOG };
#endif

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()

private:
    void InitStart(); // 在此处声明函数
};



2 在 .cpp 文件中定义 InitStart() 函数:

void CMFCApplication1Dlg::InitStart()
{
    CString strProgram = _T("C:\\Windows\\system32\\notepad.exe"); // 需要启动的程序的路径和文件名
    PROCESS_INFORMATION processInfo = { 0 };
    STARTUPINFO startupInfo = { 0 };
    startupInfo.cb = sizeof(startupInfo);

    // 启动程序
    BOOL bSuccess = CreateProcess(strProgram, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);

    if (bSuccess)
    {
        // 延迟等待程序启动完全
        Sleep(4000);

        // 获取控件的位置和大小
        CRect rc;
        GetDlgItem(IDC_STATIC)->GetWindowRect(&rc); // 这里假设 IDC_STATIC 是要嵌入程序的控件 ID
        ScreenToClient(rc);

        // 查找程序的窗口句柄
        HWND hWnd = NULL;
        while (!hWnd)
        {
            hWnd = ::FindWindow(NULL, _T("Untitled - Notepad")); // 标题栏上显示的窗口标题
        }

        if (hWnd)
        {
            // 修改窗口样式
            LONG style = GetWindowLong(hWnd, GWL_STYLE);
            style &= ~WS_CAPTION;
            style &= ~WS_THICKFRAME;
            SetWindowLong(hWnd, GWL_STYLE, style);

            // 将程序窗口嵌入到控件中
            ::SetParent(hWnd, GetDlgItem(IDC_STATIC)->m_hWnd);
            ::MoveWindow(hWnd, rc.left, rc.top, rc.Width(), rc.Height(), true);
            ::ShowWindow(hWnd, SW_SHOW);
        }
    }
}


请注意,FindWindow() 函数的第二个参数应该是您要嵌入的程序的窗口标题,而不是您的 MFC 对话框标题。在此代码中,我假设 Untitled - Notepad 是嵌入的程序的窗口标题。

3 修改 OnInitDialog() 函数,调用 InitStart() 函数:

BOOL CMFCApplication1Dlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
// 调用 InitStart() 函数
InitStart();

// 设置窗口图标
SetIcon(m_hIcon, TRUE);         // 设置大图标
SetIcon(m_hIcon, FALSE);        // 设置小图标

// TODO: 在此添加额外的初始化代码

return TRUE;    // 除非将焦点设置到控件,否则返回 TRUE
}

其中,InitStart() 函数可以是您定义的任何初始化函数,用于初始化对话框中的控件和数据。

参考GPT和自己的思路:

根据您的代码和问题描述,可能的原因是缺少定义或引用。在您的代码中,您声明了一个名为“InitStart”的函数,但是您没有实际定义它。因此,在您的OnInitDialog函数中调用此函数时,将出现未知标识符的错误。

为了解决此问题,您可以在C ++文件中实现InitStart函数。建议将它放在类的外部。此外,您可能还需要添加一些必要的头文件,如windows.h,afxwin.h和resource.h。

另外,您还需要定义StartProcess函数,或在代码中引用其定义,以便在初始化窗口时调用该函数执行第三方可执行文件。在您提供的代码中,StartProcess函数似乎只是返回“hProcess”,并没有实际完成任何其他操作。因此,您需要检查StartProcess函数的实现,以确保它正确执行。

最后,您可能还需要检查您的配置文件“resouces.h”,以确保您正确定义了STD_INCLUDES。如果您的代码中使用了此定义,则必须在resource.h文件中定义它。

在调试过程中,您可以查看VS调试器中的输出窗口以查看详细错误消息。这将有助于您确定是哪个文件、行或函数引发了错误,以及出错的具体原因。

参考GPT和自己的思路,你的代码中出现 "identifier not found" 的错误可能是因为你在 StartProcess 函数中使用了一个未定义的标识符 hProcess。你需要将 StartProcess 函数的返回语句改为返回 processInfo.hProcess,而不是 hProcess。

以下是已修正的 StartProcess 函数代码:

HANDLE StartProcess(LPCTSTR program, LPCTSTR args)
{
    HANDLE hProcess = NULL;
    PROCESS_INFORMATION processInfo;
    STARTUPINFO startupInfo;
    ZeroMemory(&startupInfo, sizeof(startupInfo));
    startupInfo.cb = sizeof(startupInfo);
    if (CreateProcess(program, (LPTSTR)args,
        NULL,  // 进程安全性
        NULL,  // 线程安全性
        FALSE, // 不继承句柄
        0,     // 无启动标志
        NULL,  // 无特殊环境
        NULL,  // 默认启动目录
        &startupInfo,
        &processInfo))
        hProcess = processInfo.hProcess;
    return hProcess;
}

此外,你的代码中可能还存在以下问题:

1.在返回进程句柄之前,你应该检查 CreateProcess 函数调用是否成功。否则,你可能会得到一个无效的句柄。

2.hwnd 变量永远不会被设置为 NULL,因为 while(!hwnd) 循环会一直运行,直到找到一个窗口句柄。为了避免无限循环,你应该添加一个超时或限制循环的条件。

3.你使用 SWP_HIDEWINDOW 标志来设置窗口位置,这会在显示窗口后立即隐藏它。如果你想显示窗口,应该将此标志去掉。

希望这可以帮到你!

不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
在代码中调用了一个名为StartProcess的函数,然而并未定义该函数,因此会报错“找不到标识符 StartProcess”。可以在代码中添加该函数的定义以解决此问题。同时,需要注意在定义该函数时,返回一个HANDLE类型的句柄值。

以下是一个例子:

HANDLE StartProcess(LPCTSTR program, LPCTSTR args)
{
    HANDLE hProcess = NULL;
    PROCESS_INFORMATION processInfo;
    STARTUPINFO startupInfo;
    ::ZeroMemory(&startupInfo, sizeof(startupInfo));
    startupInfo.cb = sizeof(startupInfo);
    if (::CreateProcess(program, (LPTSTR)args,
        NULL,  // process security
        NULL,  // thread security
        FALSE, // no inheritance
        0,     // no startup flags
        NULL,  // no special environment
        NULL,  // default startup directory
        &startupInfo,
        &processInfo))
    {
        hProcess = processInfo.hProcess;
    }
    return hProcess;
}

此外,可以加入一些错误处理逻辑来检查CreateProcess函数的返回值以及processInfo.hProcess的值是否属于有效或正确的句柄值。例如:

HANDLE StartProcess(LPCTSTR program, LPCTSTR args)
{
    HANDLE hProcess = NULL;
    PROCESS_INFORMATION processInfo;
    STARTUPINFO startupInfo;
    ::ZeroMemory(&startupInfo, sizeof(startupInfo));
    startupInfo.cb = sizeof(startupInfo);
    if (::CreateProcess(program, (LPTSTR)args,
        NULL,  // process security
        NULL,  // thread security
        FALSE, // no inheritance
        0,     // no startup flags
        NULL,  // no special environment
        NULL,  // default startup directory
        &startupInfo,
        &processInfo))
    {
        if (processInfo.hProcess != NULL && processInfo.hProcess != INVALID_HANDLE_VALUE)
        {
            hProcess = processInfo.hProcess;
        }
        else
        {
            DWORD error = ::GetLastError();
            TRACE(_T("Failed to get process handle: %d\n"), error);
        }
    }
    else
    {
        DWORD error = ::GetLastError();
        TRACE(_T("Failed to start process: %d\n"), error);
    }
    return hProcess;
}

如果我的回答解决了您的问题,请采纳!