Files
shgxtzcjhoudaosaomadayinwpf/RIZO_Application/RIZO_Application.Infrastructure/Util/BartenderHelper/BartenderPrintHelper.cs

335 lines
11 KiB
C#
Raw Normal View History

2025-05-15 11:22:42 +08:00
using Microsoft.SqlServer.Server;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
2025-05-15 11:22:42 +08:00
using System.Threading.Tasks;
namespace linesider_screen_tool
{
public sealed class BartenderPrintHelper : IDisposable
{
private const string BarTenderProgId = "BarTender.Application";
private object? _btApp; // 声明为可空类型
private int _disposedValue;
2025-05-15 11:22:42 +08:00
public BartenderPrintHelper()
{
// 延迟初始化,在首次使用时创建 Bartender 应用实例
}
/// <summary>
/// 打印单个标签(同步)
/// </summary>
public bool PrintLabel(
string templatePath,
Dictionary<string, string> subStringValues,
int copies = 1,
int serializedLabels = 1)
{
ValidateParameters(templatePath, subStringValues);
return ExecuteBartenderAction(format =>
{
SetPrintSettings(format, copies, serializedLabels);
SetSubStringValues(format, subStringValues);
InvokeMethod(format, "PrintOut", false, false);
return true;
}, templatePath);
}
2025-05-15 11:22:42 +08:00
public Task<List<string>> GetNamedSubStrings(string templatePath)
{
dynamic format =null;
dynamic btApp = null;
try
{
btApp = Activator.CreateInstance(Type.GetTypeFromProgID(BarTenderProgId));
format = btApp.Formats.Open(
templatePath,
false,
null
);
format.PrintSetup.IdenticalCopiesOfLabel = 1;
format.PrintSetup.NumberSerializedLabels = 1;
List<string> subStrings = new List<string>();
dynamic namedSubStrings = format.NamedSubStrings;
foreach (var iteam in namedSubStrings)
{
subStrings.Add(iteam.Name);
}
return Task.FromResult(subStrings);
}
catch (Exception ex)
{
Console.WriteLine($"发生错误: {ex.Message}");
return null;
}
finally
{
// 清理资源
if (format != null)
{
Marshal.ReleaseComObject(format);
}
if (btApp != null)
{
btApp.Quit(0);
2025-05-15 14:23:02 +08:00
Marshal.ReleaseComObject(btApp);
2025-05-15 11:22:42 +08:00
}
}
}
/// <summary>
/// 批量打印标签(高性能实现)
/// </summary>
public bool PrintBatchLabels(
string templatePath,
IEnumerable<Dictionary<string, string>> labelsData,
int copiesPerLabel = 1,
int serializedLabels = 1)
{
ValidateParameters(templatePath, labelsData);
return ExecuteBartenderAction(format =>
{
SetPrintSettings(format, copiesPerLabel, serializedLabels);
bool allSuccess = true;
foreach (var data in labelsData)
{
try
{
SetSubStringValues(format, data);
InvokeMethod(format, "PrintOut", false, false);
}
catch (Exception ex)
{
allSuccess = false;
LogError($"打印标签时出错: {ex.Message}");
}
}
return allSuccess;
}, templatePath);
}
private T ExecuteBartenderAction<T>(Func<object, T> action, string templatePath)
{
if (IsDisposed)
throw new ObjectDisposedException(nameof(BartenderPrintHelper));
EnsureBartenderInitialized();
object? format = null;
try
{
format = OpenFormat(templatePath);
return action(format!);
}
catch (Exception ex)
{
LogError($"执行 Bartender 操作失败: {ex.Message}");
throw new InvalidOperationException("Bartender 操作失败", ex);
}
finally
{
ReleaseFormat(format);
}
}
private void EnsureBartenderInitialized()
{
if (_btApp == null)
{
try
{
_btApp = Activator.CreateInstance(Type.GetTypeFromProgID(BarTenderProgId));
SetProperty(_btApp, "Visible", false); // 确保应用程序不可见
}
catch (Exception ex)
{
LogError($"初始化 Bartender 失败: {ex.Message}");
throw new InvalidOperationException("无法初始化 Bartender 应用程序", ex);
}
}
}
private object OpenFormat(string path)
{
EnsureBartenderInitialized();
try
{
var formats = GetProperty(_btApp!, "Formats");
return InvokeMethod(formats, "Open", path, false, null);
}
catch (Exception ex)
{
LogError($"打开标签模板失败: {path}, 错误: {ex.Message}");
throw new FileNotFoundException($"无法打开标签模板: {path}", ex);
}
}
private void SetPrintSettings(object format, int copies, int serializedLabels)
{
var printSetup = GetProperty(format, "PrintSetup");
SetProperty(printSetup, "IdenticalCopiesOfLabel", copies);
SetProperty(printSetup, "NumberSerializedLabels", serializedLabels);
}
private void SetSubStringValues(object format, Dictionary<string, string> values)
{
if (values == null) return;
foreach (var kv in values)
{
try
{
InvokeMethod(format, "SetNamedSubStringValue", kv.Key, kv.Value);
}
catch (Exception ex)
{
LogError($"设置标签变量失败: {kv.Key}={kv.Value}, 错误: {ex.Message}");
throw new ArgumentException($"无法设置标签变量: {kv.Key}", ex);
}
}
}
private void ReleaseFormat(object? format)
{
if (format == null) return;
try
{
InvokeMethod(format, "Close", 0); // 0 = BarTender.BtSaveOptions.btDoNotSaveChanges
}
catch (Exception ex)
{
LogError($"关闭标签格式失败: {ex.Message}");
}
finally
{
ReleaseComObject(format);
}
}
private void ReleaseComObject(object obj)
{
if (obj == null || !Marshal.IsComObject(obj))
return;
try
{
// 循环调用直到引用计数为 0
int refCount;
while ((refCount = Marshal.ReleaseComObject(obj)) > 0)
{
LogError($"COM 对象引用计数: {refCount}");
}
}
catch (Exception ex)
{
LogError($"释放 COM 对象失败: {ex.Message}");
}
}
private void ValidateParameters(string templatePath, object data = null)
{
if (string.IsNullOrEmpty(templatePath))
throw new ArgumentNullException(nameof(templatePath), "标签模板路径不能为空");
if (!File.Exists(templatePath))
throw new FileNotFoundException("指定的标签模板文件不存在", templatePath);
if (data is IEnumerable<Dictionary<string, string>> labelsData && labelsData == null)
throw new ArgumentNullException(nameof(labelsData), "标签数据不能为空");
if (data is Dictionary<string, string> singleLabelData && singleLabelData == null)
throw new ArgumentNullException(nameof(singleLabelData), "标签数据不能为空");
}
private void LogError(string message)
{
// 这里可以添加实际的日志记录逻辑
Console.WriteLine($"[ERROR] {message}");
}
private bool IsDisposed => Interlocked.CompareExchange(ref _disposedValue, 0, 0) != 0;
public void Dispose()
{
// 使用 Interlocked.Exchange 确保线程安全
if (Interlocked.Exchange(ref _disposedValue, 1) != 0)
return;
try
{
// 使用临时变量确保线程安全
var btApp = Interlocked.Exchange(ref _btApp, null);
if (btApp != null && Marshal.IsComObject(btApp))
{
try
{
// 使用反射调用 Quit 方法
InvokeMethod(btApp, "Quit", 0);
}
catch (Exception ex)
{
LogError($"退出 Bartender 应用程序失败: {ex.Message}");
}
finally
{
ReleaseComObject(btApp);
}
}
}
finally
{
GC.SuppressFinalize(this);
}
}
~BartenderPrintHelper() => Dispose();
// 反射辅助方法
private object GetProperty(object obj, string propertyName)
{
return obj.GetType().InvokeMember(
propertyName,
BindingFlags.GetProperty,
null,
obj,
null
)!;
}
private void SetProperty(object obj, string propertyName, object value)
{
obj.GetType().InvokeMember(
propertyName,
BindingFlags.SetProperty,
null,
obj,
new[] { value }
);
}
private object InvokeMethod(object obj, string methodName, params object?[]? parameters)
{
return obj.GetType().InvokeMember(
methodName,
BindingFlags.InvokeMethod,
null,
obj,
parameters ?? Array.Empty<object>()
)!;
}
}
}