我写的第一个labview 展示页面程序

期间也遇到很多问题:

使用了豆包和千问回答问题基本相似,使用activeX,使用在左侧的 工具箱 (Toolbox) 中找到你之前添加的 National Instruments CW UI Control。(这个方法一直没有找到控件的问题,处理了很久)后来依据豆包的答案使用 ativeX 的方法实际是通过 LabVIEW 的 ActiveX 服务器接口,C# 可以直接打开 VI 并操控前面板控件,甚至把前面板窗口嵌入到 WinForms 窗体里实际是运行起来强制使用win32API放到对应的Form窗体里。

第二种方式:

首先明确:LabVIEW 2024 已经没有「工具 → 转换 → 生成 .NET 控件」这个功能了。NI 在较新版本中移除了直接把 VI 前面板打包成 .NET UserControl 的能力。(根据追问情况 说是 2015以后得版本都没有这个功能跟个,但是我下载了 8.6版以及2012版安装完了以后一样没有这个菜单功能)

第三种方法:

LabVIEW 菜单:工具 → 选项 → 服务器:Web 服务器 / VI 服务器

确认 VI 服务器已启用,TCP/IP 勾选(操作了一遍实际上就是将web页面转换成image来展示)

所以我选择第一中方式:

其中意义就是用ActiveX应用打开VI然后将VI强制转入到Form窗体内:

需要解决的问题:

1.去掉VI页面上的菜单栏(这个试过很多方法依然无法解决,没有办法只能把在移动的时候网上提了个48DPI).

2.要确定打开应用的句柄查找的方式:

用 Spy++ 工具查看真实类名

Visual Studio 自带「Spy++」工具(工具栏 → 工具 → Spy++)打开后按查找窗口,拖到 LabVIEW 前面板上,就能看到准确的类名和标题(据说还可以

csharp 复制代码
IntPtr lvHwnd = (IntPtr)vi.FrontPanel.NativeWindow; 

那句柄但是我好像没有找到。)

先要引入COM

添加 LabVIEW COM 引用Visual Studio 右键项目 → 添加 → COM 引用

勾选「National Instruments LabVIEW 2024 Type Library」(版本号对应你的 LabVIEW)

点确定,项目里会多出一个 LabVIEW 的引用

完整代码如下:

csharp 复制代码
public partial class Form2 : Form
{
    // 查找窗口
    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);


    [DllImport("user32.dll")]
    public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll")]
    public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

    [DllImport("user32.dll")]
    public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
        int X, int Y, int cx, int cy, uint uFlags);

    [DllImport("user32.dll")]
    public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

    [DllImport("user32.dll")]
    public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
    // Win10/11 去掉 DWM 阴影边框(可选)
    [DllImport("dwmapi.dll")]
    static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr,
        ref int attrValue, int attrSize);

    [DllImport("user32.dll")]
    static extern IntPtr GetMenu(IntPtr hWnd);

    [DllImport("user32.dll")]
    static extern bool SetMenu(IntPtr hWnd, IntPtr hMenu);

    [DllImport("user32.dll")]
    static extern bool DrawMenuBar(IntPtr hWnd);


    // 常量
    const int GWL_STYLE = -16;
    const int GWL_EXSTYLE = -20;

    // 窗口样式位
    const uint WS_CAPTION = 0x00C00000;       // 标题栏
    const uint WS_THICKFRAME = 0x00040000;    // 可调边框
    const uint WS_BORDER = 0x00800000;        // 细边框
    const uint WS_DLGFRAME = 0x00400000;      // 对话框边框
    const uint WS_SYSMENU = 0x00080000;       // 系统菜单(右上角按钮)
    const uint WS_MINIMIZEBOX = 0x00020000;   // 最小化按钮
    const uint WS_MAXIMIZEBOX = 0x00010000;   // 最大化按钮

    const uint WS_EX_DLGMODALFRAME = 0x00000001; // 扩展边框
    const int DWMWA_NCRENDERING_POLICY = 2;
    const int DWMNCRP_DISABLED = 1;

    const uint SWP_NOMOVE = 0x0002;
    const uint SWP_NOSIZE = 0x0001;
    const uint SWP_NOZORDER = 0x0004;
    const uint SWP_FRAMECHANGED = 0x0020;    // 关键:强制重新计算非客户区

    int menuBarHeight = -48; // 根据实际调整,一般 20~28 像素菜单剪切 需要双倍的剪切


    public Form2()
    {
        InitializeComponent();
    }


    private IntPtr _lvHwnd;
    private dynamic _lvApp;
    private dynamic _vi;



    private void button1_Click(object sender, EventArgs e)
    {
        //// 1. 创建 LabVIEW ActiveX 对象
        //Type lvType = Type.GetTypeFromProgID("LabVIEW.Application");
        //_lvApp = Activator.CreateInstance(lvType);

        //// 2. 打开 VI
        //string viPath = @"C:\Projects\MyTestVI.vi";
        //_vi = _lvApp.VIs.Open(viPath);

        //// 3. 显示前面板
        //_vi.FrontPanel.Visible = true;
        LabVIEW.Application lv = new LabVIEW.ApplicationClass();

        LabVIEW.VirtualInstrument vi = lv.GetVIReference(System.Windows.Forms.Application.StartupPath + "\\LabViewFiles\\26072301.vi", "", false);
        vi.FPWinOpen = true;//打开前面板
        vi.SetControlValue("风扇", true); //设定控件值
        //var myValue = vi.GetControlValue("指示器名称");
         vi.Run(false);//打开当前VI
        vi.OpenFrontPanel(true,LabVIEW.FPStateEnum.eMaximized);



        // 4. 稍等窗口创建完成
        System.Threading.Thread.Sleep(500);

        // 5. 查找前面板窗口句柄
        // 方法A:按窗口标题找(标题就是 VI 文件名)
        _lvHwnd = FindWindow(null, "26072301.vi 前面板");

        // 方法B:如果知道类名,更准确
        // _lvHwnd = FindWindow("LVFrontPanelClass", "MyTestVI.vi");

        if (_lvHwnd == IntPtr.Zero)
        {
            MessageBox.Show("找不到前面板窗口");
            return;
        }

        //// 6. 去掉窗口标题栏和边框
        //RemoveTitleBarAndBorder(_lvHwnd);

        //// 7. 嵌入到 Panel 容器里
        //SetParent(_lvHwnd, PanelMain.Handle);

        //// 8. 调整大小填满容器
        //MoveWindow(_lvHwnd, 0, 0, PanelMain.Width, PanelMain.Height, true);

        ///一次性使用放入面板
        ///
        EmbedLabVIEW(_lvHwnd,PanelMain);


    }

    public void   RemoveTitleBarAndBorder(IntPtr hWnd)
    {
        // 1. 读取当前样式
        int style = GetWindowLong(hWnd, GWL_STYLE);
        style &= ~(int)(WS_CAPTION | WS_THICKFRAME | WS_BORDER | WS_DLGFRAME | WS_SYSMENU); 

        SetWindowLong(hWnd, GWL_STYLE, style);

        SetWindowPos(hWnd, IntPtr.Zero, 0, 0, 0, 0,
            SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);

        // 5. 【关键】强制窗口重新计算边框(否则改了不生效)
        SetWindowPos(hWnd, IntPtr.Zero, 0, 0, 0, 0,
            SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
        //去掉菜单栏
        IntPtr hMenu = GetMenu(hWnd);
        if (hMenu != IntPtr.Zero)
        {
            SetMenu(hWnd, IntPtr.Zero);  // 设为空菜单
            DrawMenuBar(hWnd);           // 重绘,让改动生效
        }
        // 6. Win10/11 可选:去掉 DWM 阴影
        int val = DWMNCRP_DISABLED;
        DwmSetWindowAttribute(hWnd, DWMWA_NCRENDERING_POLICY, ref val, 4);
    }
    public void EmbedLabVIEW(IntPtr lvHwnd, Control container)
    {
        // 1. 去掉标题栏和边框
        int style = GetWindowLong(lvHwnd, GWL_STYLE);
        style &= ~(int)(WS_CAPTION | WS_THICKFRAME | WS_BORDER | WS_DLGFRAME | WS_SYSMENU);
        SetWindowLong(lvHwnd, GWL_STYLE, style);

        SetWindowPos(lvHwnd, IntPtr.Zero, 0, 0, 0, 0,
            SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);

        // 2. 去掉菜单栏
        IntPtr hMenu = GetMenu(lvHwnd);
        if (hMenu != IntPtr.Zero)
        {
            SetMenu(lvHwnd, IntPtr.Zero);
            DrawMenuBar(lvHwnd);
        }

        // 3. 嵌入容器
        SetParent(lvHwnd, container.Handle);
        MoveWindow(lvHwnd, 0, menuBarHeight, container.Width, container.Height- menuBarHeight, true);
    }

    private void Form2_SizeChanged(object sender, EventArgs e)
    {

    }

    private void PanelMain_SizeChanged(object sender, EventArgs e)
    {
        if (_lvHwnd != IntPtr.Zero)
        {
            MoveWindow(_lvHwnd, 0, menuBarHeight, PanelMain.Width, PanelMain.Height - menuBarHeight, true);
        }
    }
}
相关推荐
电气_空空5 小时前
基于 LabVIEW的数据采集与信号处理系统的设计
嵌入式硬件·毕业设计·信号处理·labview
无垠的广袤1 天前
【RA-Eco-RA4M2开发板】步进电机的串口控制和 LabVIEW 数据采集
单片机·嵌入式硬件·labview
fanchenxinok1 天前
基于图莫斯的CAN UDS升级上位机-LabVIEW版本(八):TOOMOSS_SID85_ControlDTCSetting.vi — DTC控制
can·labview·uds刷写·图莫斯
fanchenxinok1 天前
基于图莫斯的CAN UDS升级上位机-LabVIEW版本(十一):LogManager.vi — 日志管理
can·labview·uds刷写·图莫斯
fanchenxinok1 天前
基于图莫斯的CAN UDS升级上位机-LabVIEW版本(九):TOOMOSS_SID2E_WriteDataByID.vi — 写入数据
can·labview·uds刷写
fanchenxinok2 天前
基于图莫斯的CAN UDS升级上位机-LabVIEW版本:从零搭建ECU刷写工具
labview·uds升级·升级上位机
fanchenxinok2 天前
基于图莫斯的CAN UDS升级上位机-LabVIEW版本(一):TOOMOSS_OpenDev(CAN).vi — 设备打开与句柄管理
labview
fanchenxinok2 天前
基于图莫斯的CAN UDS升级上位机-LabVIEW版本(四):TOOMOSS_SID27_SecurityAccess.vi — 安全访问
安全·labview·uds升级·子vi
马不啼2 天前
NI HIL自动化测试10-Labview04-树形结构
labview·simulink·hil·veristand·teststand