当前位置: 首页 > news >正文

期货软件开发「启动加载页 / 初始化窗口」

一、初始化窗口

作用:

• 程序刚打开时显示

• 后台连接行情服务器

• 加载历史 K 线 / 行情数据

• 加载完成后自动进入主界面

二、当前已实现的核心功能

1. 窗体基础功能

• 无边框拖动(顶部栏按住可移动窗口)

• 最小化按钮 •

关闭按钮

• 基于 Sunny.UI 样式的界面

2. 初始化与线程加载

• 窗体一打开,自动启动后台线程

• 线程里调用 Common.Init() 初始化行情系统

• 把当前窗口句柄传给底层,用于接收消息

• 线程设为后台线程,程序退出自动结束

3. Windows 消息接收

1. WM_SHOW_INFO:显示提示文字(加载中…)

2. WM_NET_MSG_HQ:接收行情服务器的网络消息

这是 C# 与 C++ 底层 / 行情接口 通信的标准方式。

4. 行情网络消息处理(最关键) 当前能处理这些服务器消息:

① 连接状态 • msg=1:开始加载数据 / 连接失败 • msg=2:服务器断开

② 数据推送(msg=3)

• cmd="2":心跳包(保持连接)

• cmd="10":实时行情推送

• cmd="11":K 线数据推送

• cmd="102":历史行情请求返回

• cmd="103":正在下载历史 K 线 → 显示 “正在加载数据 {合约代码}”

• cmd="104":历史数据全部下载完成 → 显示 “数据加载完成”,并返回 DialogResult.OK → 自动关闭并进入主程序

• cmd="105":补充行情数据

• cmd="106":补充数据下载完成

5. 安全更新 UI

• 封装了 UpdateControlSafely()

• 跨线程更新标签文字,不会报错、不会卡死

6. 异常保护

• 所有消息处理都包了 try-catch

• 出错会弹出提示,不会导致整个程序崩溃 7. 资源释放

• 窗体关闭时尝试终止加载线程

• 避免线程泄漏

namespace newQiHuo { public partial class FrmInit : Form { private Thread _loadDataThread; // 保存线程引用 private CancellationTokenSource _cts; // 线程取消令牌源,替代Abort // 定义结构体(补充代码完整性,实际项目中应该在公共区域定义) public struct ST_NetMsg { public int msg; // 消息类型 public int datalen; // 数据长度 public string data; // 数据内容 // 补充其他必要字段... } public FrmInit() { InitializeComponent(); _cts = new CancellationTokenSource(); // 初始化取消令牌 } private void FrmInit_Load(object sender, EventArgs e) { Common.gRecvHQNetMsgHandle = this.Handle; // 初始化线程并设置为后台线程 _loadDataThread = new Thread(() => InitLoadData(this.Handle, _cts.Token)); _loadDataThread.IsBackground = true; // 后台线程,程序退出时自动终止 _loadDataThread.Start(); } // 初始化加载数据线程(增加取消令牌支持) private static void InitLoadData(IntPtr handle, CancellationToken token) { try { Common.Init(handle); // 轮询取消信号,优雅退出 while (!token.IsCancellationRequested) { Thread.Sleep(100); // 避免空循环占用CPU } } catch (OperationCanceledException) { // 捕获取消异常,正常退出 Common.ShowMsg("数据加载线程已正常终止"); } catch (Exception ex) { Common.ShowMsg($"数据加载线程异常:{ex.Message}"); } } protected override void DefWndProc(ref System.Windows.Forms.Message m) { switch (m.Msg) { case Global.WM_SHOW_INFO: // 显示消息 OnShowInfo(m.WParam, m.LParam); break; case Global.WM_NET_MSG_HQ: OnNetMsgHQ(m.WParam, m.LParam); break; default: base.DefWndProc(ref m); break; } } // 安全更新UI控件的通用方法 private void UpdateControlSafely(Action action) { if (this.IsDisposed) return; // 防止窗体已释放时调用Invoke if (this.InvokeRequired) // 判断是否跨线程 { // 使用BeginInvoke避免线程阻塞(如果不需要等待UI更新完成) this.BeginInvoke(action); } else { action(); // 已经是UI线程,直接执行 } } // 行情网络消息处理 protected void OnNetMsgHQ(IntPtr wParam, IntPtr lParam) { try { // 空指针检查 if (lParam == IntPtr.Zero) return; // 从非托管内存解析结构体 ST_NetMsg myNetMsg = (ST_NetMsg)Marshal.PtrToStructure(lParam, typeof(ST_NetMsg)); if (myNetMsg.msg == 1) { if (myNetMsg.datalen == 0) { UpdateControlSafely(() => lbInfo.Text = "开始加载数据..."); } else { Common.ShowMsg("行情服务器连接失败"); } } else if (myNetMsg.msg == 2) { Common.ShowMsg("行情服务器连接断开"); } else if (myNetMsg.msg == 3) { string strData = myNetMsg.data?.Trim() ?? string.Empty; // 空值保护 if (string.IsNullOrEmpty(strData)) return; // 修复:正确的Split用法 - 移除空元素 string[] vec = strData.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); if (vec.Length < 3) return; string cmd = vec[0]; if (cmd == "2") // 心跳返回 { } else if (cmd == "10") // 实时行情推送 { string code = vec[1]; string timeStamp = vec[2]; } else if (cmd == "11") // K线推送 { } else if (cmd == "102") // 获取历史行情请求返回 { string errCode = vec[1]; string errMsg = vec[2]; } else if (cmd == "103") // 历史行情数据 { if (vec.Length < 12) return; string code = vec[1]; string timeStamp = vec[2]; string period = vec[3]; // 安全更新UI UpdateControlSafely(() => lbInfo.Text = $"正在加载数据 {code}"); } else if (cmd == "104") // 历史数据下载完成 { if (vec.Length < 3) return; string errCode = vec[1]; string errMsg = vec[2]; Common.gKlineHistoryManage.DownloadHistoryFinished(); // 安全更新UI并设置DialogResult UpdateControlSafely(() => { lbInfo.Text = "数据加载完成"; this.DialogResult = DialogResult.OK; }); } else if (cmd == "105") // 补充数据 { if (vec.Length < 12) return; string code = vec[1]; string timeStamp = vec[2]; string period = vec[3]; } else if (cmd == "106") // 补充数据下载完成 { if (vec.Length < 7) return; string errCode = vec[1]; string errMsg = vec[2]; string code = vec[3]; string period = vec[4]; } } } catch (Exception ex) { // 异常捕获,避免消息处理崩溃 Common.ShowMsg($"行情消息处理出错:{ex.Message}"); } } // 显示消息 protected void OnShowInfo(IntPtr wParam, IntPtr lParam) { try { if (lParam == IntPtr.Zero) return; // 空指针检查 ST_NetMsg myNetMsg = (ST_NetMsg)Marshal.PtrToStructure(lParam, typeof(ST_NetMsg)); string strInfo = myNetMsg.data ?? string.Empty; // 安全更新UI UpdateControlSafely(() => lbInfo.Text = strInfo); } catch (Exception ex) { Common.ShowMsg($"信息显示出错:{ex.Message}"); } } private void butMin_Click(object sender, EventArgs e) { this.WindowState = FormWindowState.Minimized; } private void butclos_Click(object sender, EventArgs e) { this.Close(); } private Point formPoint; private void Toptaskbar_MouseDown(object sender, MouseEventArgs e) { formPoint = new Point(e.X, e.Y); } private void Toptaskbar_MouseMov(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { this.Location = new Point(this.Location.X + e.X - formPoint.X, this.Location.Y + e.Y - formPoint.Y); } } // 窗体关闭时释放资源 protected override void OnFormClosing(FormClosingEventArgs e) { base.OnFormClosing(e); // 优雅取消线程,替代Abort if (_cts != null) { _cts.Cancel(); _cts.Dispose(); } // 等待线程结束(可选,根据实际需求) if (_loadDataThread != null && _loadDataThread.IsAlive) { // 最多等待1秒,避免程序卡死 _loadDataThread.Join(1000); _loadDataThread = null; } } // 窗体释放时的清理 protected override void Dispose(bool disposing) { if (disposing) { _cts?.Dispose(); components?.Dispose(); } base.Dispose(disposing); } } // 补充必要的公共类定义(实际项目中应该在单独文件) public static class Common { public static IntPtr gRecvHQNetMsgHandle; public static KlineHistoryManage gKlineHistoryManage = new KlineHistoryManage(); public static void Init(IntPtr handle) { // 实际初始化逻辑 } public static void ShowMsg(string msg) { // 实际消息显示逻辑 MessageBox.Show(msg); } } public class KlineHistoryManage { public void DownloadHistoryFinished() { // 实际逻辑 } } public static class Global { public const int WM_SHOW_INFO = 0x0400 + 100; // 自定义消息 public const int WM_NET_MSG_HQ = 0x0400 + 101; } }
http://www.jsqmd.com/news/472838/

相关文章:

  • Python抓取广东省各城市租房数据并存储
  • 【研报216】2026年智能驾驶产业市场趋势与用户需求分析:AI 重构汽车价值链
  • 基于springboot城市智慧养犬管理平台
  • 4-Kotlin核心语法-数据类与密封类
  • 为什么防御 DDoS 攻击的成本这么高?
  • 基于AWS CAF构建标准化云治理体系,助力企业实现安全合规与可持续优化
  • CTF保姆级教程:从零基础到参赛拿奖,2026年最全指南!
  • 花8000买的商标竟是“废标”?内行人教你3步避开90%的坑
  • Java字符串反转,统计字符串中字符类型及频次
  • 爬虫识别与防御
  • Flutter 三方库 icc_parser 的鸿蒙化适配指南 - 高效解析 ICC 颜色配置文件,精准还原跨平台色彩表现
  • 原儿茶醛市场洞察:2026 - 2032年复合增长率(CAGR)为4.6%
  • 三相电压型SVPWM整流器仿真与控制策略分析,双闭环PID控制,输出电压600V(可自行调节)...
  • 氛围编程的一些体会
  • 权威认证 + 实战教学 守嘉职业技能三大热门培训 为健康产业输送专业人才 - 品牌排行榜单
  • OpenClaw Runtime 源码级解析:从 CLI 到 Agent Execution Engine
  • P1908 逆序对
  • Oracle 故障应急处理手册-RAC 投票盘(Voting Disk)故障恢复
  • Flutter 三方库 rabbit_converter 的鸿蒙化适配指南 - 让消息转换回归“工业化标准”,打造鸿蒙应用专家级的 RabbitMQ 数据适配中台
  • OpenClaw:打开文献综述宝库的钥匙——引用方法与技巧详解
  • SLAM公式中双竖线 ||·|| 表示什么意思?一文搞懂范数的含义
  • 甘肃2026上半年软考报名时间已出!
  • 院墙上的监控成摆设?避开这三个坑,不给骗子留机会!室外监控摄像头哪个品牌好
  • Boost源码分析: Serialization
  • 国产化解决方案!鼎讯信通 射频信号源模块 DXSL系列
  • 哺乳动物为什么不长绿毛
  • next-dbm:审批可控、部署高效,解锁数据构建更新新范式
  • 广西选物业律师实践经验分享,效果看得见!
  • 计算机毕业设计springboot基于Java的校园问题反馈系统 基于Spring Boot框架的高校师生诉求处理与服务平台的设计与实现 基于Java Web的校园意见收集与问题跟踪管理系统开发与应用
  • 鱼眼相机标定矫正详细步骤