From fedbe94e36a3c7ba0419eea23a104c0e170f4c45 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 1 Aug 2025 07:35:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DPDMS=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E9=97=AE=E9=A2=98=EF=BC=8C=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E6=97=B6=E8=87=AA=E5=8A=A8=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用正确的Aveva.ApplicationFramework.IAddin接口 - 在Start方法中直接弹出欢迎对话框 - 移除自定义接口定义,使用AVEVA官方接口 - 插件现在可以在PDMS启动时正常加载并显示 - 添加.gitignore忽略VS临时文件 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .gitignore | 77 ++++++++++++ CLAUDE.md | 96 +++++++++++++++ Class1.cs | 60 ++++++++++ Properties/AssemblyInfo.cs | 33 ++++++ Readme.md | 234 +++++++++++++++++++++++++++++++++++++ TellmePdmsPluging.csproj | 75 ++++++++++++ TellmePdmsPluging.sln | 31 +++++ 7 files changed, 606 insertions(+) create mode 100644 .gitignore create mode 100644 CLAUDE.md create mode 100644 Class1.cs create mode 100644 Properties/AssemblyInfo.cs create mode 100644 Readme.md create mode 100644 TellmePdmsPluging.csproj create mode 100644 TellmePdmsPluging.sln diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..31c5bf8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,77 @@ +# Visual Studio +.vs/ +bin/ +obj/ +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# Visual Studio cache files +*.VisualState.xml + +# Resharper +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity +_TeamCity* + +# DotCover +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/Html2 +DocProject/Help/html + +# Publish Web Output +*.Publish.xml + +# NuGet Packages Directory +packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +[Bb]in +[Oo]bj +sql +TestResults +[Tt]est[Rr]esult* +*.Cache +ClientBin +[Ss]tyle[Cc]op.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..6ee153c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,96 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## 项目概述 + +这是一个专为AVEVA PDMS 12.1 SP4设计的远程控制插件项目,目标是实现单前端客户端对单个PDMS会话的远程操控功能。 + +## 技术约束 + +- **目标框架**: .NET Framework 3.5 (由于PDMS 12.1 SP4的兼容性要求) +- **平台架构**: x86 (32位) - PDMS不支持64位DLL加载 +- **编译配置**: Debug/Release 均为AnyCPU,但需注意实际运行环境限制 + +## 项目架构 + +### 核心组件设计 +根据README.md中的技术方案,系统采用以下架构: +- **HttpListener服务器**: 基于System.Net.HttpListener的自托管HTTP服务 +- **线程安全队列**: SafeQueue实现HTTP线程到PDMS主线程的命令传递 +- **命令模式**: ICommand接口抽象化PDMS API调用 +- **插件接口**: IAddin实现PDMS插件规范 + +### 通信模型 +``` +前端 → HTTP请求 → HttpListener → SafeQueue → PDMS主线程 → PDMS API +``` + +## 开发命令 + +### 构建项目 +```bash +# 使用MSBuild构建解决方案 +msbuild TellmePdmsPluging.sln /p:Configuration=Debug /p:Platform="Any CPU" + +# 或使用Visual Studio命令行工具 +devenv TellmePdmsPluging.sln /Build Debug +``` + +### 发布版本 +```bash +msbuild TellmePdmsPluging.sln /p:Configuration=Release /p:Platform="Any CPU" +``` + +## 关键实现要点 + +### 线程安全要求 +- **绝对禁止**在HttpListener线程中直接调用PDMS API +- 所有PDMS API调用必须在主线程执行 +- 使用SafeQueue进行线程间通信 + +### 内存管理 +- 由于.NET 3.5的内存限制,需要考虑Large Address Aware (LAA)配置 +- 大数据操作时需要实现分页和流式传输 +- 定期执行GC.Collect()以释放内存 + +### API设计原则 +根据技术方案,主要API端点包括: +- `/health` - 健康检查 +- `/command` - 即时命令执行 +- `/task` - 长任务管理 +- `/stats` - 统计数据获取 +- `/export/ifc` - 模型导出 + +## 部署要求 + +### PDMS集成 +- 编译输出的DLL需要复制到PDMS安装目录 +- 需要修改`DesignAddin.xml`配置文件注册插件 +- 确保使用x86架构编译以兼容PDMS要求 + +### 网络配置 +- HTTP服务默认监听localhost:9001端口 +- 仅允许本地连接,外网访问需通过反向代理 + +## 性能优化指导 + +### 大模型处理 +- 使用分区查询减少内存占用 +- 实现数据流式传输避免内存峰值 +- 支持后台任务执行和进度查询 + +### 资源释放 +- 及时释放PDMS对象引用 +- 监控内存使用情况,超过阈值时发出重启警告 + +## 开发注意事项 + +- 严格遵循.NET 3.5 API限制,避免使用高版本特性 +- 所有异步操作使用.NET 3.5兼容的方式实现 +- 优先使用BCL内置组件,减少第三方依赖 +- 遵循PDMS插件开发规范和线程安全要求 + +## 项目工作流程 + +- 所有的编译和测试由用户来执行 \ No newline at end of file diff --git a/Class1.cs b/Class1.cs new file mode 100644 index 0000000..54fe8dd --- /dev/null +++ b/Class1.cs @@ -0,0 +1,60 @@ +using Aveva.ApplicationFramework; +using System; +using System.Windows.Forms; + +namespace TellmePdmsPluging +{ + public class TellmePdmsAddin : IAddin + { + public string Name + { + get + { + return "TellmePdmsAddin"; + } + } + + public string Description + { + get + { + return "PDMS远程控制插件"; + } + } + + /// + /// 程序打开时,会调用这个方法 + /// + /// + public void Start(ServiceManager serviceManager) + { + try + { + // 直接弹出窗口,不需要按钮 + MessageBox.Show("TellmePdms插件已成功加载!\n准备启动HTTP服务器...", "插件加载成功", MessageBoxButtons.OK, MessageBoxIcon.Information); + + // 记录日志 + System.IO.File.WriteAllText(@"C:\temp\pdms_plugin_log.txt", + $"Plugin loaded successfully at {DateTime.Now}\r\n"); + } + catch (Exception ex) + { + try + { + System.IO.File.WriteAllText(@"C:\temp\pdms_plugin_error.txt", + $"Plugin Error at {DateTime.Now}: {ex.Message}\r\n{ex.StackTrace}\r\n"); + } + catch { } + MessageBox.Show($"插件加载错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// + /// 程序关闭时,会调用这个方法 + /// + public void Stop() + { + // 插件停止时的清理操作 + } + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3bccc8b --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("TellmePdmsPluging")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TellmePdmsPluging")] +[assembly: AssemblyCopyright("Copyright © 2025")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("5e040389-82ef-4a66-942e-a65817cab55f")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..f45fd24 --- /dev/null +++ b/Readme.md @@ -0,0 +1,234 @@ + + +## 思考: + +**Laying out the plan** + +I'm mapping out a detailed remote control system for PDMS 12.1 SP4, covering architecture, technology options, component details, and operational steps. + +**Pinpointing project specifics** + +I'm detailing the technology stack, threading model, communication protocols, API design, data models, error handling, build/instructions, security, workflow, monitoring, and the timeline for development.**Laying out the plan** + +I'm mapping out a detailed remote control system for PDMS 12.1 SP4, covering architecture, technology options, component details, and operational steps. + +**Pinpointing project specifics** + +I'm detailing the technology stack, threading model, communication protocols, API design, data models, error handling, build/instructions, security, workflow, monitoring, and the timeline for development.**Laying out the plan** + +I'm mapping out a detailed remote control system for PDMS 12.1 SP4, covering architecture, technology options, component details, and operational steps. + +**Pinpointing project specifics** + +I'm detailing the technology stack, threading model, communication protocols, API design, data models, error handling, build/instructions, security, workflow, monitoring, and the timeline for development. + +Reasoned for 4m 31s + + + +## 回答 + +下面是一份可直接交给 PDMS 技术团队实施的 **“单前端 → 单 PDMS 12.1 SP4 会话远程操控”** 完整方案。内容包括总体目标、技术选型、详细架构、接口规范、关键代码骨架、开发与部署步骤、性能与运维要点,以及里程碑计划。 + +--- + +## 1. 项目目标与边界 + +| 项目维度 | 约束 / 目标 | +|---|---| +| **软件版本** | AVEVA PDMS 12.1 SP4(32‑bit) | +| **并发模型** | 仅一个前端客户端控制一个 PDMS 会话,无多用户并发 | +| **模型规模** | 可能包含千万级元件,单次统计/导出任务可持续数十分钟 | +| **技术栈硬性限制** | *PDMS 仅支持 .NET 3.5 x86*,高版本框架或 64‑bit DLL 将被拒载 [CSDN Blog](https://blog.csdn.net/u011498594/article/details/101690303) | +| **性能目标** | - 交互命令(< 1 s)
- 中型任务(1‑30 s)有进度回报
- 大任务可后台执行,前端可轮询进度 | +| **安全范围** | 初期仅限局域网;外网访问通过反向代理 + VPN 后续加固 | + +--- + +## 2. 技术选型概览 + +| 层次 | 选型 | 说明 | +|---|---|---| +| **通讯协议** | HTTP/1.1 + JSON/MessagePack(默认)
可选 gRPC‑C 核心库(二期) | HttpListener 属于 BCL,.NET 2.0 起即内置,完全兼容 .NET 3.5 [Microsoft Learn](https://learn.microsoft.com/en-us/dotnet/api/system.net.httplistener?view=net-9.0&utm_source=chatgpt.com) | +| **自托管服务器** | `System.Net.HttpListener`(端口 9001,仅监听 `localhost`) | +| **PDMS 插件框架** | `IAddin` 接口(须编译为 .NET 3.5 / x86 DLL) [CSDN Blog](https://blog.csdn.net/u011498594/article/details/101690303) | +| **线程隔离** | `HttpThread` → **安全队列** → `PDMS 主线程`
(队列用 `Queue + lock` 自行封装,.NET 3.5 无 ConcurrentQueue) | +| **序列化** | - 轻量:`System.Web.Script.Serialization`(内置)
- 高性能:`MsgPack‑CLI 0.5.x`(支持 .NET 3.5) | +| **日志** | `log4net 1.2.17`(支持 .NET 2.0+) | +| **大任务调度** | 简易 `TaskTable` 持久化为 `SQLite` 文件,支持重启后恢复进度 | +| **前端** | 任意:Web/Qt/WPF。只需按 REST 协议调用即可。 | + +--- + +## 3. 系统架构与流程 + +```mermaid +graph LR +A[前端 UI (浏览器/桌面)] -- HTTP --> B(HttpListener
PDMS Agent DLL) +B -- 入队 --> C[安全队列] +C -- 脱队 --> D{PDMS 主线程
Idle/CAF Command} +D --> E[PDMS API 调用] +D -- 进度/结果 --> B +B -- HTTP Response --> A +``` + +### 3.1 关键流程 +1. **监听**:Agent 在 `Start()` 中启动 `HttpListener`,仅允许 `http://localhost:9001/`。 +2. **入队**:收到请求后解析为 `ICommand` 对象写入 `SafeQueue`,立即返回 `202 Accepted + taskId`,前端开始轮询 `/task/{id}`。 +3. **执行**:主线程在 `Application.Idle`(或 CAF `Command`) 下轮询 `SafeQueue`,顺序执行命令并周期性写入进度。 +4. **结果流式返回**:长列表接口(如统计)使用 *分页或流式分块*,每� GZip 后 Base64 传输,减少内存峰值。 + +--- + +## 4. API 设计(首批 6 个端点) + +| 方法 | 路径 | 说明 | 返回 | +|---|---|---|---| +| `GET` | `/health` | 进程存活检测 + 空闲内存 | `{status:"OK", memMB:1234}` | +| `POST` | `/command` | 下达即刻命令(<1 s) | `{code:0,data:"OK"}` | +| `POST` | `/task` | 启动长任务,返回 `taskId` | `{taskId:"abc123"}` | +| `GET` | `/task/{id}` | 查询任务进度 | `{percent:42,state:"RUNNING"}` | +| `GET` | `/stats` | 流式统计接口,支持 `queryExpr`, `props[]` | `application/octet-stream`(分块) | +| `POST` | `/export/ifc` | 导出 IFC/RVM/CSV | `{downloadUrl:".../ifc.zip"}` | + +> **统一响应封装**: +> ```json +> { "code": 0, "msg": "成功", "data": {...} } +> ``` +> 错误码表放在 `ErrorCodes.cs`,与 CLAUDE.md 中的 `ApiResponse` 结构保持一致。 + +--- + +## 5. 代码骨架(精简示例) + +```csharp +// AgentAddin.cs (.NET 3.5, x86) +[Addin("HttpAgent", Description="PDMS REST Control")] +public class HttpAgentAddin : IAddin +{ + private HttpServer _server; + public string Description => "PDMS REST Agent"; + public string Name => "HttpAgent"; + public void Start(ServiceManager sm) + { + SafeQueue.Init(); // 全局单例 + _server = new HttpServer(9001); // 见下 + _server.Start(); + Application.Idle += OnIdle; // CAF 中同理 + } + public void Stop() { _server.Dispose(); } + + void OnIdle(object sender, EventArgs e) + { + while (SafeQueue.TryDequeue(out ICommand cmd)) + { + cmd.Execute(); // 必须保证只在主线程调用 PDMS API + } + } +} +``` + +```csharp +// HttpServer.cs +class HttpServer : IDisposable +{ + readonly HttpListener _l = new HttpListener(); + public HttpServer(int port) + { + _l.Prefixes.Add($"http://localhost:{port}/"); + } + public void Start() + { + _l.Start(); + _l.BeginGetContext(BeginContext, null); + } + void BeginContext(IAsyncResult ar) + { + var ctx = _l.EndGetContext(ar); + _l.BeginGetContext(BeginContext, null); // 继续监听 + + ICommand cmd = CmdFactory.Parse(ctx); // JSON => ICommand + SafeQueue.Enqueue(cmd); + + ctx.Response.StatusCode = 202; + ctx.Response.Close(); + } + public void Dispose() => _l.Close(); +} +``` + +```csharp +// SafeQueue.cs (简易线程安全队列 .NET 3.5) +static class SafeQueue +{ + static readonly Queue _q = new Queue(); + static readonly object _sync = new object(); + public static void Enqueue(ICommand c) { lock(_sync) _q.Enqueue(c); } + public static bool TryDequeue(out ICommand c) + { lock(_sync){ if(_q.Count>0){ c=_q.Dequeue(); return true; } } c=null; return false; } +} +``` + +#### 重点注意 +- **严禁在 HttpListener 线程直接操作 PDMS API**;否则 UI 会冻结甚至崩溃。 +- 如需长任务取消,可在 `ICommand` 中实现 `CancellationToken` 并于主线程检查。 + +--- + +## 6. 大模型性能优化清单 + +| 类别 | 操作 | 说明 | +|---|---|---| +| **内存** | 链接 /LARGEADDRESSAWARE;Win 64‑bit 系统上可让进程地址空间上限从 2 GB 提升到 3 GB (/3GB) [Microsoft Learn](https://learn.microsoft.com/en-us/windows/win32/memory/memory-limits-for-windows-releases) | +| **分区遍历** | 让前端传 `ZONE` / `GROUP`,内部执行 `QUERY /*`;尽量避免 `.NET` 侧逐件遍历。 | +| **流式返回** | 统计接口按 1 000 条一批序列化 → GZip → Base64;前端 `ReadableStream` 逐块解析并渲染。 | +| **后台导出** | `pdms.exe /BATCH macro.pml` 子进程执行 IFC/ISO 批导出,主会话实时返回进度。 | +| **资源释放** | 每批次后执行 `GC.Collect()` + `Utilities.Application.DoEvents()`;如内存 > 1.6 GB 发出重启警告。 | + +--- + +## 7. 开发与部署步骤 + +| 阶段 | 任务 | 负责人 | 预计耗� | +|---|---|---|---| +| **环境准备** | 安装 VS2013 + .NET 3.5 SP1、PDMS 12.1 SP4 开发版 | 运维 | 1 d | +| **Skeleton** | 创建 AgentAddin、SafeQueue、ICommand 抽象、HttpServer | 开发 | 3 d | +| **核心命令** | `HealthCmd / ExecCmd / StatsCmd / ExportCmd` | 开发 | 5 d | +| **前端 Demo** | 简易 Web 页面(Vue/React 任选)+ 轮询 Task API | 前端 | 3 d | +| **任务管理** | `TaskTable` + 进度轮询接口 | 开发 | 2 d | +| **日志/异常** | log4net 文件分卷、全局异常捕获 | 开发 | 1 d | +| **单元测试** | NUnit + MockPDMS(可选) | QA | 3 d | +| **性能测试** | 典型大模型脚本(≥500 MB MDB) | QA | 2 d | +| **文档交付** | API Swagger JSON + 部署手册 | 技术写作 | 2 d | +| **上线** | 复制 DLL → PDMS 根目录,修改 `DesignAddin.xml`;放行 9001 端口(仅 127.0.0.1)| 运维 | 0.5 d | + +*总工期预估:约 **3 周**(15 人/日)。* + +--- + +## 8. 交付物清单 + +1. `HttpAgent.dll` (PDMS 插件,x86, .NET 3.5) +2. `AgentConfig.xml`(端口、日志路径、最大批大小等可配置) +3. 前端示例项目源码 + 打包脚本 +4. REST API 文档(Swagger 2.0 / OpenAPI 3.0) +5. 《部署运维手册》:包含 LAA 打开方法、Windows 防火墙配置、日志轮转 +6. 《性能基准报告》:不同模型规模下的 CPU/内存曲线与耗时 + +--- + +## 9. 后续演进路线(可选) + +| 版本 | 规划 | 价值 | +|---|---|---| +| **v1.1** | 接入 MessagePack + Protobuf Binary Streaming | 带宽降低 50‑80 % | +| **v1.2** | WebSocket 通道(长连,实时回推进度) | 减少前端轮询 | +| **v2.0** | 升级到 AVEVA E3D(64‑bit & .NET 4.8),换用 ASP.NET Core / Kestrel | 扩展能力 + 长期官方支持 | + +--- + +### 结语 + +该方案沿用 **“命令队列 + 主线程执行”** 的线程安全模型,摒弃 OWIN/Katana 等高版本依赖,完全兼容 PDMS 12.1 SP4 的 .NET 3.5/x86 运行环境。通过 **分页/流式传输、后台子进程导出、LAA 内存扩展** 等手段,可以在单客户端场景下稳定处理超大模型,同时保留后续迁移到 E3D 的升级路径。 + +请技术团队严格按上述步骤实施,并在性能测试阶段使用真实项目数据库进行基准,以确保上线后的体验满足设计人员日常使用需求。若在实现过程中遇到 API 调用或资源释放细节问题,建议优先参考 AVEVA 官方 SDK 文档及本文引用资源。祝项目顺利! \ No newline at end of file diff --git a/TellmePdmsPluging.csproj b/TellmePdmsPluging.csproj new file mode 100644 index 0000000..e6ebd8e --- /dev/null +++ b/TellmePdmsPluging.csproj @@ -0,0 +1,75 @@ + + + + + Debug + AnyCPU + {5E040389-82EF-4A66-942E-A65817CAB55F} + Library + Properties + TellmePdmsPluging + TellmePdmsPluging + v3.5 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + full + false + bin\x86\Debug\ + DEBUG;TRACE + prompt + 4 + x86 + + + pdbonly + true + bin\x86\Release\ + TRACE + prompt + 4 + x86 + + + + ..\..\..\..\..\AVEVA\Plant\PDMS12.1.SP4\Aveva.ApplicationFramework.dll + + + ..\..\..\..\..\AVEVA\Plant\PDMS12.1.SP4\Aveva.ApplicationFramework.Presentation.Customize.dll + + + ..\..\..\..\..\AVEVA\Plant\PDMS12.1.SP4\PMLNet.dll + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TellmePdmsPluging.sln b/TellmePdmsPluging.sln new file mode 100644 index 0000000..be4a58c --- /dev/null +++ b/TellmePdmsPluging.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35303.130 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TellmePdmsPluging", "TellmePdmsPluging.csproj", "{5E040389-82EF-4A66-942E-A65817CAB55F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5E040389-82EF-4A66-942E-A65817CAB55F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E040389-82EF-4A66-942E-A65817CAB55F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E040389-82EF-4A66-942E-A65817CAB55F}.Debug|x86.ActiveCfg = Debug|x86 + {5E040389-82EF-4A66-942E-A65817CAB55F}.Debug|x86.Build.0 = Debug|x86 + {5E040389-82EF-4A66-942E-A65817CAB55F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E040389-82EF-4A66-942E-A65817CAB55F}.Release|Any CPU.Build.0 = Release|Any CPU + {5E040389-82EF-4A66-942E-A65817CAB55F}.Release|x86.ActiveCfg = Release|x86 + {5E040389-82EF-4A66-942E-A65817CAB55F}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E979C325-F34D-4225-BE85-65498F9A2887} + EndGlobalSection +EndGlobal