完全移植,但还有多处二义性错误

This commit is contained in:
zqm
2025-10-24 16:55:39 +08:00
parent fe158753af
commit 16db737f2a
5 changed files with 2482 additions and 428 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -1,11 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Drawing;
using System.Data; using System.Data;
using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using System.Threading;
namespace JoyD.Windows.CS.Toprie namespace JoyD.Windows.CS.Toprie
{ {
@@ -59,7 +60,12 @@ namespace JoyD.Windows.CS.Toprie
/// </summary> /// </summary>
private void InitializeDeviceManager() private void InitializeDeviceManager()
{ {
_deviceManager = new DeviceManager(); _deviceManager = new DeviceManager
{
AutoReconnectEnabled = true,
ReconnectInterval = 2000, // 2秒
MaxReconnectAttempts = 5
};
// 注册图像接收事件 // 注册图像接收事件
_deviceManager.ImageReceived += DeviceManager_ImageReceived; _deviceManager.ImageReceived += DeviceManager_ImageReceived;
@@ -69,6 +75,8 @@ namespace JoyD.Windows.CS.Toprie
// 注册连接异常事件 // 注册连接异常事件
_deviceManager.ConnectionException += DeviceManager_ConnectionException; _deviceManager.ConnectionException += DeviceManager_ConnectionException;
} }
/// <summary> /// <summary>
@@ -81,34 +89,98 @@ namespace JoyD.Windows.CS.Toprie
} }
/// <summary> /// <summary>
/// 启动并连接设备 /// 启动相机
/// </summary> /// </summary>
public void StartCamera() public void StartCamera()
{ {
try try
{ {
// 设置为热图模式 // 只有在没有接收图像时才启动
_deviceManager.CurrentImageMode = ImageMode.Thermal; if (!_isReceivingImage)
// 启用自动重连
_deviceManager.AutoReconnectEnabled = true;
// 连接设备
bool connected = _deviceManager.ConnectDevice();
if (connected)
{ {
// 开始接收图像 // 清理错误显示
StartReceiveImage(); ShowError(string.Empty);
// 使用异步方式连接设备和设置模式避免UI线程阻塞
ThreadPool.QueueUserWorkItem(delegate
{
try
{
// 设置为热图模式
bool modeSet = false;
try
{
_deviceManager.SetImageMode(ImageMode.Thermal);
modeSet = true;
Console.WriteLine("已设置热图模式");
}
catch (Exception ex)
{
Console.WriteLine($"设置热图模式失败: {ex.Message}");
}
// 启用自动重连
_deviceManager.AutoReconnectEnabled = true;
// 尝试连接设备
if (_deviceManager.ConnectDevice())
{
Console.WriteLine("设备连接成功");
// 如果热图模式未成功设置,在连接成功后再次尝试
if (!modeSet)
{
try
{
_deviceManager.SetImageMode(ImageMode.Thermal);
Console.WriteLine("连接后已设置热图模式");
}
catch (Exception ex)
{
Console.WriteLine($"连接后设置热图模式失败: {ex.Message}");
}
}
// 在连接成功后开始接收图像
this.Invoke(new Action(() =>
{
// 再次检查是否已在UI线程设置为接收状态
if (!_isReceivingImage)
{
StartReceiveImage();
}
}));
}
else
{
// 连接失败时显示错误
string errorMsg = "设备连接失败,请检查设备状态或网络连接";
this.Invoke(new Action(() => ShowError(errorMsg)));
Console.WriteLine(errorMsg);
}
}
catch (Exception ex)
{
// 捕获所有异常,防止后台线程崩溃
string errorMsg = $"启动相机异常: {ex.Message}";
this.Invoke(new Action(() => ShowError(errorMsg)));
Console.WriteLine(errorMsg);
Console.WriteLine(ex.StackTrace);
}
});
Console.WriteLine("相机启动流程已开始");
} }
else else
{ {
ShowError("无法连接到设备,请检查设备是否在线"); Console.WriteLine("相机已在运行状态");
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
ShowError($"启动相机失败: {ex.Message}"); ShowError($"启动相机失败: {ex.Message}");
Console.WriteLine($"启动相机主流程错误: {ex.Message}");
Console.WriteLine(ex.StackTrace);
} }
} }
@@ -155,36 +227,176 @@ namespace JoyD.Windows.CS.Toprie
/// </summary> /// </summary>
private void DeviceManager_ImageReceived(object sender, ImageReceivedEventArgs e) private void DeviceManager_ImageReceived(object sender, ImageReceivedEventArgs e)
{ {
if (this.InvokeRequired) // 不在这里使用using因为我们需要将图像传递给UI线程
Image image = e.ImageData;
if (image == null)
{ {
// 在UI线程上更新图像 Console.WriteLine("接收到空图像数据");
this.Invoke(new Action(() => UpdateImage(e.ImageData))); return;
} }
else
try
{ {
UpdateImage(e.ImageData); // 尝试创建图像的克隆以传递给UI线程
Image clonedImage = null;
try
{
clonedImage = (Image)image.Clone();
// 验证克隆的图像是否有效
if (clonedImage.Width <= 0 || clonedImage.Height <= 0)
{
Console.WriteLine("克隆的图像尺寸无效");
clonedImage.Dispose();
image.Dispose(); // 确保原始图像也被释放
return;
}
}
catch (Exception ex)
{
Console.WriteLine($"克隆图像失败: {ex.Message}");
image.Dispose(); // 确保原始图像被释放
return;
}
// 确保在UI线程上更新并且检查控件是否已被释放
if (!this.IsDisposed && !this.Disposing)
{
if (this.InvokeRequired)
{
try
{
// 使用BeginInvoke在UI线程上更新图像避免可能的死锁问题
this.BeginInvoke(new Action(() =>
{
try
{
UpdateImageOnUI(clonedImage);
}
catch (Exception ex)
{
Console.WriteLine($"更新UI图像失败: {ex.Message}");
// 如果UI更新失败确保克隆的图像被释放
if (clonedImage != null)
{
clonedImage.Dispose();
}
}
}));
}
catch (Exception)
{
// 异常情况下确保释放图像资源
clonedImage?.Dispose();
throw;
}
}
else
{
// 在UI线程上直接更新图像
UpdateImageOnUI(clonedImage);
}
}
else
{
// 如果控件已释放,确保释放图像资源
clonedImage.Dispose();
}
// 释放原始图像资源
image.Dispose();
}
catch (Exception ex)
{
Console.WriteLine($"处理图像接收事件失败: {ex.Message}");
// 确保在任何异常情况下都释放原始图像
if (image != null)
{
try
{
image.Dispose();
}
catch {}
}
} }
} }
/// <summary> /// <summary>
/// 更新图像显示 /// 在UI线程上更新图像
/// </summary> /// </summary>
private void UpdateImage(Image image) private void UpdateImageOnUI(Image image)
{ {
// 空值检查
if (image == null)
{
Console.WriteLine("传入UpdateImageOnUI的图像为空");
return;
}
try try
{ {
// 释放之前的图像资源 // 更新图像前先检查控件是否存在/已释放
if (imageBox.Image != null) if (this.IsDisposed || imageBox == null || imageBox.IsDisposed)
{ {
imageBox.Image.Dispose(); // 如果控件已释放,确保图像也被释放
image.Dispose();
Console.WriteLine("控件已释放,无法更新图像");
return;
} }
// 设置新图像 // 保存旧图像引用,以便在设置新图像后释放
imageBox.Image = (Image)image.Clone(); Image oldImage = imageBox.Image;
try
{
// 尝试设置新图像
imageBox.Image = image;
// 验证图像是否成功设置
if (imageBox.Image != image)
{
Console.WriteLine("图像设置失败,可能参数无效");
image.Dispose(); // 释放未成功设置的图像
return;
}
// 仅在新图像成功设置后释放旧图像
if (oldImage != null && oldImage != image) // 防止自引用释放
{
oldImage.Dispose();
}
}
catch (ArgumentException ex) when (ex.Message.Contains("参数无效"))
{
// 特别处理"参数无效"异常
Console.WriteLine($"图像参数无效: {ex.Message}");
image.Dispose(); // 释放无效图像
// 尝试设置旧图像回来,如果可能的话
if (oldImage != null)
{
try
{
imageBox.Image = oldImage;
}
catch
{
// 如果设置旧图像也失败,释放它
oldImage.Dispose();
}
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"更新图像失败: {ex.Message}"); Console.WriteLine($"更新图像UI失败: {ex.Message}");
// 确保在任何异常情况下都释放传入的图像资源
try
{
image.Dispose();
}
catch {}
} }
} }
@@ -193,13 +405,26 @@ namespace JoyD.Windows.CS.Toprie
/// </summary> /// </summary>
private void DeviceManager_ConnectionStatusChanged(object sender, ConnectionStatusChangedEventArgs e) private void DeviceManager_ConnectionStatusChanged(object sender, ConnectionStatusChangedEventArgs e)
{ {
if (this.InvokeRequired) // 确保在UI线程上更新并且检查控件是否已被释放
if (!this.IsDisposed && !this.Disposing)
{ {
this.Invoke(new Action(() => HandleConnectionStatusChanged(e))); if (this.InvokeRequired)
} {
else try
{ {
HandleConnectionStatusChanged(e); // 使用BeginInvoke代替Invoke避免可能的死锁问题
this.BeginInvoke(new Action(() => HandleConnectionStatusChanged(e)));
}
catch (ObjectDisposedException)
{
// 捕获控件已释放异常,避免程序崩溃
Console.WriteLine("控件已释放跳过UI更新");
}
}
else
{
HandleConnectionStatusChanged(e);
}
} }
} }
@@ -208,10 +433,28 @@ namespace JoyD.Windows.CS.Toprie
/// </summary> /// </summary>
private void HandleConnectionStatusChanged(ConnectionStatusChangedEventArgs e) private void HandleConnectionStatusChanged(ConnectionStatusChangedEventArgs e)
{ {
// 更新UI状态
UpdateUIState(e.NewStatus == ConnectionStatus.Connected);
switch (e.NewStatus) switch (e.NewStatus)
{ {
case ConnectionStatus.Connected: case ConnectionStatus.Connected:
Console.WriteLine("设备已连接"); Console.WriteLine("设备已连接");
// 清除错误信息
ShowError(string.Empty);
// 确保设置为热图模式
try
{
_deviceManager.SetImageMode(ImageMode.Thermal);
Console.WriteLine("连接成功后确认热图模式");
}
catch (Exception ex)
{
Console.WriteLine($"连接成功后设置热图模式失败: {ex.Message}");
}
if (!_isReceivingImage) if (!_isReceivingImage)
{ {
StartReceiveImage(); StartReceiveImage();
@@ -219,31 +462,109 @@ namespace JoyD.Windows.CS.Toprie
break; break;
case ConnectionStatus.Disconnected: case ConnectionStatus.Disconnected:
Console.WriteLine("设备已断开连接"); Console.WriteLine("设备已断开连接");
_isReceivingImage = false;
// 停止接收图像
if (_isReceivingImage)
{
_deviceManager.StopReceiveImage();
_isReceivingImage = false;
}
if (!string.IsNullOrEmpty(e.Message)) if (!string.IsNullOrEmpty(e.Message))
{ {
ShowError(e.Message); ShowError(e.Message);
}
else
{
ShowError("设备连接已断开");
} }
break; break;
case ConnectionStatus.Connecting: case ConnectionStatus.Connecting:
case ConnectionStatus.Reconnecting: case ConnectionStatus.Reconnecting:
Console.WriteLine("正在连接设备..."); Console.WriteLine($"正在连接设备...{(!string.IsNullOrEmpty(e.Message) ? " " + e.Message : "")}");
ShowError(string.Empty); // 清除之前的错误信息
break; break;
} }
} }
/// <summary>
/// 更新UI状态
/// </summary>
/// <param name="isConnected">是否已连接</param>
private void UpdateUIState(bool isConnected)
{
try
{
// 根据连接状态更新图像框状态
if (imageBox != null && !imageBox.IsDisposed)
{
if (isConnected)
{
imageBox.BorderStyle = BorderStyle.FixedSingle;
}
else
{
imageBox.BorderStyle = BorderStyle.Fixed3D;
}
}
// 更新图像框的边框颜色,提供视觉反馈
if (imageBox != null)
{
imageBox.BorderStyle = isConnected ? BorderStyle.FixedSingle : BorderStyle.Fixed3D;
// 可选:设置不同的边框颜色以提供更好的视觉反馈
if (isConnected)
{
imageBox.BackColor = Color.LightGreen;
}
else
{
imageBox.BackColor = Color.LightGray;
}
}
Console.WriteLine($"UI状态已更新为: {(isConnected ? "" : "")}");
}
catch (Exception ex)
{
Console.WriteLine($"更新UI状态时出错: {ex.Message}");
}
}
/// <summary> /// <summary>
/// 设备管理器连接异常事件处理 /// 设备管理器连接异常事件处理
/// </summary> /// </summary>
private void DeviceManager_ConnectionException(object sender, ConnectionExceptionEventArgs e) private void DeviceManager_ConnectionException(object sender, ConnectionExceptionEventArgs e)
{ {
if (this.InvokeRequired) // 确保在UI线程上更新并且检查控件是否已被释放
if (!this.IsDisposed && !this.Disposing)
{ {
this.Invoke(new Action(() => ShowError($"连接异常: {e.ContextMessage}"))); if (this.InvokeRequired)
} {
else try
{ {
ShowError($"连接异常: {e.ContextMessage}"); // 使用BeginInvoke在UI线程上显示错误
this.BeginInvoke(new Action(() =>
{
// 记录异常日志
Console.WriteLine($"连接异常发生于 {e.Timestamp}: {e.ContextMessage}\n{e.Exception.Message}\n{e.Exception.StackTrace}");
ShowError($"连接异常: {e.ContextMessage}");
}));
}
catch (ObjectDisposedException)
{
// 捕获控件已释放异常,避免程序崩溃
Console.WriteLine("控件已释放,跳过异常处理");
}
}
else
{
// 记录异常日志
Console.WriteLine($"连接异常发生于 {e.Timestamp}: {e.ContextMessage}\n{e.Exception.Message}\n{e.Exception.StackTrace}");
ShowError($"连接异常: {e.ContextMessage}");
}
} }
} }
@@ -257,8 +578,19 @@ namespace JoyD.Windows.CS.Toprie
// 可以根据需要添加UI上的错误显示 // 可以根据需要添加UI上的错误显示
// 这里简化处理,只在控制台输出 // 这里简化处理,只在控制台输出
// 检查imageBox是否存在且尺寸有效
if (imageBox == null || imageBox.Width <= 0 || imageBox.Height <= 0)
{
Console.WriteLine("imageBox尺寸无效跳过错误显示图像创建");
return;
}
// 确保使用有效的尺寸创建Bitmap
int width = Math.Max(100, imageBox.Width);
int height = Math.Max(100, imageBox.Height);
// 如果需要在图像区域显示错误文字,可以使用以下代码 // 如果需要在图像区域显示错误文字,可以使用以下代码
using (Bitmap errorBitmap = new Bitmap(imageBox.Width, imageBox.Height)) using (Bitmap errorBitmap = new Bitmap(width, height))
using (Graphics g = Graphics.FromImage(errorBitmap)) using (Graphics g = Graphics.FromImage(errorBitmap))
{ {
g.Clear(Color.Black); g.Clear(Color.Black);
@@ -272,7 +604,7 @@ namespace JoyD.Windows.CS.Toprie
g.DrawString(message, font, brush, textLocation); g.DrawString(message, font, brush, textLocation);
} }
UpdateImage(errorBitmap); UpdateImageOnUI(errorBitmap);
} }
// 启动定时器3秒后清除错误显示 // 启动定时器3秒后清除错误显示
@@ -287,7 +619,19 @@ namespace JoyD.Windows.CS.Toprie
{ {
_errorDisplayTimer.Stop(); _errorDisplayTimer.Stop();
// 清除错误显示,恢复到等待图像状态 // 清除错误显示,恢复到等待图像状态
using (Bitmap waitingBitmap = new Bitmap(imageBox.Width, imageBox.Height))
// 检查imageBox是否存在且尺寸有效
if (imageBox == null || imageBox.Width <= 0 || imageBox.Height <= 0)
{
Console.WriteLine("imageBox尺寸无效跳过等待图像创建");
return;
}
// 确保使用有效的尺寸创建Bitmap
int width = Math.Max(100, imageBox.Width);
int height = Math.Max(100, imageBox.Height);
using (Bitmap waitingBitmap = new Bitmap(width, height))
using (Graphics g = Graphics.FromImage(waitingBitmap)) using (Graphics g = Graphics.FromImage(waitingBitmap))
{ {
g.Clear(Color.Black); g.Clear(Color.Black);
@@ -302,7 +646,7 @@ namespace JoyD.Windows.CS.Toprie
g.DrawString(waitingText, font, brush, textLocation); g.DrawString(waitingText, font, brush, textLocation);
} }
UpdateImage(waitingBitmap); UpdateImageOnUI(waitingBitmap);
} }
} }
@@ -330,9 +674,12 @@ namespace JoyD.Windows.CS.Toprie
// 取消注册事件并释放设备管理器 // 取消注册事件并释放设备管理器
if (_deviceManager != null) if (_deviceManager != null)
{ {
// 移除所有事件监听
_deviceManager.ImageReceived -= DeviceManager_ImageReceived; _deviceManager.ImageReceived -= DeviceManager_ImageReceived;
_deviceManager.ConnectionStatusChanged -= DeviceManager_ConnectionStatusChanged; _deviceManager.ConnectionStatusChanged -= DeviceManager_ConnectionStatusChanged;
_deviceManager.ConnectionException -= DeviceManager_ConnectionException; _deviceManager.ConnectionException -= DeviceManager_ConnectionException;
// 释放设备管理器资源
_deviceManager.Dispose(); _deviceManager.Dispose();
_deviceManager = null; _deviceManager = null;
} }
@@ -346,7 +693,7 @@ namespace JoyD.Windows.CS.Toprie
} }
// 无论是否在设计模式下,都需要释放图像资源 // 无论是否在设计模式下,都需要释放图像资源
if (imageBox.Image != null) if (imageBox != null && !imageBox.IsDisposed && imageBox.Image != null)
{ {
imageBox.Image.Dispose(); imageBox.Image.Dispose();
imageBox.Image = null; imageBox.Image = null;

File diff suppressed because it is too large Load Diff

View File

@@ -25,6 +25,9 @@
<IncludeBuildOutput>true</IncludeBuildOutput> <IncludeBuildOutput>true</IncludeBuildOutput>
<IncludeContentInPack>true</IncludeContentInPack> <IncludeContentInPack>true</IncludeContentInPack>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Toprie.ico</ApplicationIcon>
</PropertyGroup>
<!-- 添加NuGet打包支持 --> <!-- 添加NuGet打包支持 -->
<Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" /> <Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />
<!-- 确保项目支持pack目标 --> <!-- 确保项目支持pack目标 -->
@@ -74,5 +77,8 @@
<DependentUpon>Camera.cs</DependentUpon> <DependentUpon>Camera.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Include="Toprie.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> </Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB