修复PDMS插件加载问题,实现启动时自动弹窗

- 使用正确的Aveva.ApplicationFramework.IAddin接口
- 在Start方法中直接弹出欢迎对话框
- 移除自定义接口定义,使用AVEVA官方接口
- 插件现在可以在PDMS启动时正常加载并显示
- 添加.gitignore忽略VS临时文件

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root 2025-08-01 07:35:46 +08:00
commit fedbe94e36
7 changed files with 606 additions and 0 deletions

77
.gitignore vendored Normal file
View File

@ -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

96
CLAUDE.md Normal file
View File

@ -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插件开发规范和线程安全要求
## 项目工作流程
- 所有的编译和测试由用户来执行

60
Class1.cs Normal file
View File

@ -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远程控制插件";
}
}
/// <summary>
/// 程序打开时,会调用这个方法
/// </summary>
/// <param name="serviceManager"></param>
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);
}
}
/// <summary>
/// 程序关闭时,会调用这个方法
/// </summary>
public void Stop()
{
// 插件停止时的清理操作
}
}
}

View File

@ -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")]

234
Readme.md Normal file
View File

@ -0,0 +1,234 @@
<think>
## 思考:
**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
</think>
## 回答
下面是一份可直接交给PDMS技术团队实施的 **“单前端PDMS12.1SP4会话远程操控”** 完整方案。内容包括总体目标、技术选型、详细架构、接口规范、关键代码骨架、开发与部署步骤、性能与运维要点,以及里程碑计划。
---
## 1. 项目目标与边界
| 项目维度 | 约束 / 目标 |
|---|---|
| **软件版本** | AVEVAPDMS12.1SP432bit |
| **并发模型** | 仅一个前端客户端控制一个PDMS会话无多用户并发 |
| **模型规模** | 可能包含千万级元件,单次统计/导出任务可持续数十分钟 |
| **技术栈硬性限制** | *PDMS 仅支持 .NET 3.5 x86*,高版本框架或 64bit DLL 将被拒载 [CSDN Blog](https://blog.csdn.net/u011498594/article/details/101690303) |
| **性能目标** | - 交互命令(< 1s<br>- 中型任务130s有进度回报<br>- 大任务可后台执行,前端可轮询进度 |
| **安全范围** | 初期仅限局域网;外网访问通过反向代理 + VPN 后续加固 |
---
## 2. 技术选型概览
| 层次 | 选型 | 说明 |
|---|---|---|
| **通讯协议** | HTTP/1.1 + JSON/MessagePack默认<br>可选 gRPCC 核心库(二期) | HttpListener 属于 BCL.NET 2.0 起即内置,完全兼容 .NET3.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` 接口(须编译为 .NET3.5 / x86 DLL [CSDN Blog](https://blog.csdn.net/u011498594/article/details/101690303) |
| **线程隔离** | `HttpThread`**安全队列**`PDMS 主线程`<br>(队列用 `Queue<T> + lock` 自行封装,.NET 3.5 无 ConcurrentQueue |
| **序列化** | - 轻量:`System.Web.Script.Serialization`(内置)<br>- 高性能:`MsgPackCLI 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 <br>PDMS Agent DLL)
B -- 入队 --> C[安全队列]
C -- 脱队 --> D{PDMS 主线程<br>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. **结果流式返回**:长列表接口(如统计)使用 *分页或流式分块*<EFBFBD> GZip 后 Base64 传输,减少内存峰值。
---
## 4. API 设计(首批 6 个端点)
| 方法 | 路径 | 说明 | 返回 |
|---|---|---|---|
| `GET` | `/health` | 进程存活检测 + 空闲内存 | `{status:"OK", memMB:1234}` |
| `POST` | `/command` | 下达即刻命令(<1s | `{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<T>` 结构保持一致。
---
## 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<ICommand> _q = new Queue<ICommand>();
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. 大模型性能优化清单
| 类别 | 操作 | 说明 |
|---|---|---|
| **内存** | 链接 /LARGEADDRESSAWAREWin 64bit 系统上可让进程地址空间上限从 2GB 提升到 3GB (/3GB) [Microsoft Learn](https://learn.microsoft.com/en-us/windows/win32/memory/memory-limits-for-windows-releases) |
| **分区遍历** | 让前端传 `ZONE` / `GROUP`,内部执行 `QUERY /*`;尽量避免 `.NET` 侧逐件遍历。 |
| **流式返回** | 统计接口按 1000条一批序列化 → GZip → Base64前端 `ReadableStream` 逐块解析并渲染。 |
| **后台导出** | `pdms.exe /BATCH macro.pml` 子进程执行 IFC/ISO 批导出,主会话实时返回进度。 |
| **资源释放** | 每批次后执行 `GC.Collect()` + `Utilities.Application.DoEvents()`;如内存 >1.6GB 发出重启警告。 |
---
## 7. 开发与部署步骤
| 阶段 | 任务 | 负责人 | 预计耗<E8AEA1> |
|---|---|---|---|
| **环境准备** | 安装 VS2013 + .NET 3.5 SP1、PDMS12.1SP4 开发版 | 运维 | 1d |
| **Skeleton** | 创建 AgentAddin、SafeQueue、ICommand 抽象、HttpServer | 开发 | 3d |
| **核心命令** | `HealthCmd / ExecCmd / StatsCmd / ExportCmd` | 开发 | 5d |
| **前端 Demo** | 简易 Web 页面Vue/React 任选)+ 轮询 Task API | 前端 | 3d |
| **任务管理** | `TaskTable` + 进度轮询接口 | 开发 | 2d |
| **日志/异常** | log4net 文件分卷、全局异常捕获 | 开发 | 1d |
| **单元测试** | NUnit + MockPDMS可选 | QA | 3d |
| **性能测试** | 典型大模型脚本≥500MB MDB | QA | 2d |
| **文档交付** | API Swagger JSON + 部署手册 | 技术写作 | 2d |
| **上线** | 复制 DLL → PDMS 根目录,修改 `DesignAddin.xml`;放行 9001 端口 127.0.0.1| 运维 | 0.5d |
*总工期预估:约 **3周**15人/日)。*
---
## 8. 交付物清单
1. `HttpAgent.dll`PDMS 插件x86, .NET3.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 | 带宽降低 5080% |
| **v1.2** | WebSocket 通道(长连,实时回推进度) | 减少前端轮询 |
| **v2.0** | 升级到 AVEVAE3D64bit & .NET4.8),换用 ASP.NET Core / Kestrel | 扩展能力 + 长期官方支持 |
---
### 结语
该方案沿用 **“命令队列 + 主线程执行”** 的线程安全模型,摒弃 OWIN/Katana 等高版本依赖,完全兼容 PDMS12.1SP4 的 .NET3.5/x86 运行环境。通过 **分页/流式传输、后台子进程导出、LAA 内存扩展** 等手段,可以在单客户端场景下稳定处理超大模型,同时保留后续迁移到 E3D 的升级路径。
请技术团队严格按上述步骤实施,并在性能测试阶段使用真实项目数据库进行基准,以确保上线后的体验满足设计人员日常使用需求。若在实现过程中遇到 API 调用或资源释放细节问题,建议优先参考 AVEVA 官方 SDK 文档及本文引用资源。祝项目顺利!

75
TellmePdmsPluging.csproj Normal file
View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{5E040389-82EF-4A66-942E-A65817CAB55F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TellmePdmsPluging</RootNamespace>
<AssemblyName>TellmePdmsPluging</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="Aveva.ApplicationFramework">
<HintPath>..\..\..\..\..\AVEVA\Plant\PDMS12.1.SP4\Aveva.ApplicationFramework.dll</HintPath>
</Reference>
<Reference Include="Aveva.ApplicationFramework.Presentation.Customize">
<HintPath>..\..\..\..\..\AVEVA\Plant\PDMS12.1.SP4\Aveva.ApplicationFramework.Presentation.Customize.dll</HintPath>
</Reference>
<Reference Include="PMLNet">
<HintPath>..\..\..\..\..\AVEVA\Plant\PDMS12.1.SP4\PMLNet.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

31
TellmePdmsPluging.sln Normal file
View File

@ -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