删除已退役的 cadcj 旧 AutoCAD 插件目录(csproj 零引用,安装包升级本就自动清理它;含 Form3/新建项目 等旧副本与运行残留,5.33MB/31 文件)

This commit is contained in:
dqb-dev
2026-10-02 02:04:55 +08:00
parent 5e2493fdf4
commit e7f25a8ceb
28 changed files with 0 additions and 16809 deletions
Binary file not shown.
-350
View File
@@ -1,350 +0,0 @@
// ============================================================
// CAD 2018 插件入口(cadcj.dll)
// · 实现 IExtensionApplication,在 CAD 启动时自动加载
// · 注册命令 "CADCJ" 打开 Form3 报价窗口
// · 使用 PaletteSet 把 Form3 嵌成 CAD 可停靠工具栏窗口
// 启动时自动贴靠到 CAD 左侧,用户可拖到右/上/下边或浮动
// · 编译:/target:library /platform:x64
// · 加载:在 CAD 里 NETLOAD 选择 cadcj.dll,然后输入 CADCJ 命令
// ============================================================
using System;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Windows;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
[assembly: CommandClass(typeof(MyApp.CadPlugin))]
[assembly: ExtensionApplication(typeof(MyApp.CadPlugin))]
namespace MyApp
{
/// <summary>
/// CAD 2018 插件入口。CAD 启动时自动初始化,注册 CADCJ 命令打开报价窗口。
/// 报价窗口用 PaletteSet 承载,可像 CAD 工具选项板一样停靠/浮动。
/// </summary>
public class CadPlugin : IExtensionApplication
{
// PaletteSet 单例:CAD 里常驻,可停靠
private static PaletteSet _ps = null;
// Form3 单例(作为 PaletteSet 的内容)
private static Form3 _form3 = null;
// ★ 宿主容器:PaletteSet 只加 Panel,Form3 塞进去(规避主题同步崩溃)
private static System.Windows.Forms.Panel _hostPanel = null;
#region IExtensionApplication 成员
public void Initialize()
{
// ★ 最简单的文件日志,不依赖任何外部代码,确认 Initialize 是否被调用
try
{
string logPath = System.IO.Path.Combine(
System.IO.Path.GetDirectoryName(
new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath),
"cadcj_load.log");
System.IO.File.WriteAllText(logPath,
"[" + System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "] Initialize 被调用" + System.Environment.NewLine);
}
catch { }
// ★ 解决 CAD 安全提示:把插件目录添加到 TRUSTEDPATHS,并关闭 SECURELOAD
// 这样 CAD 不会每次都弹"始终加载/加载一次"的安全提示
try
{
string pluginDir = System.IO.Path.GetDirectoryName(
new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc != null)
{
// ★ 关闭 SECURELOAD(0=不检查可执行文件签名)
try
{
object sl = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("SECURELOAD");
if (sl == null || Convert.ToInt32(sl) != 0)
{
Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("SECURELOAD", 0);
}
}
catch { }
// ★ 把插件目录添加到 TRUSTEDPATHS
object cur = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("TRUSTEDPATHS");
string curPaths = cur == null ? "" : cur.ToString();
bool found = false;
string[] parts = curPaths.Split(';');
foreach (string p in parts)
{
if (string.Equals(p.Trim(), pluginDir.Trim(), System.StringComparison.OrdinalIgnoreCase))
{
found = true;
break;
}
}
if (!found)
{
string newPaths = string.IsNullOrEmpty(curPaths) ? pluginDir : curPaths + ";" + pluginDir;
Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("TRUSTEDPATHS", newPaths);
}
}
}
catch (System.Exception ex)
{
try
{
var doc0 = AcAp.DocumentManager.MdiActiveDocument;
if (doc0 != null) doc0.Editor.WriteMessage("\n[CADCJ] 设置可信路径失败: " + ex.Message);
}
catch { }
}
try
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc != null)
{
doc.Editor.WriteMessage("\n[CADCJ] 成套报价插件已加载,报价窗口将随文档自动打开。");
}
// ★ 监听文档创建/激活事件:每次新建/打开文件时自动显示报价窗口
AcAp.DocumentManager.DocumentCreated += OnDocumentCreated;
// ★ 关键修复:acaddoc.lsp 的 NETLOAD 发生在文档已打开之后,
// DocumentCreated 事件早已错过;且 Idle 事件在挂接时若 CAD 已空闲
// 可能永不触发 → 改为直接显示(Initialize 在命令上下文里可安全创建 UI)
if (AcAp.DocumentManager.MdiActiveDocument != null && _ps == null && _form3 == null)
{
PluginLog("[Initialize] 直接调用 OpenForm3");
OpenForm3();
}
}
catch (System.Exception ex2)
{
PluginLog("[Initialize] ⚠ 直接打开失败: " + ex2.Message);
}
}
/// <summary>文档创建时自动打开/显示报价窗口(停靠左侧)。</summary>
private void OnDocumentCreated(object sender, DocumentCollectionEventArgs e)
{
try
{
// 延迟到 Idle 时执行,避免在文档创建过程中操作 UI
AcAp.Idle -= OnCadIdleShowPalette;
AcAp.Idle += OnCadIdleShowPalette;
}
catch { }
}
/// <summary>Idle 时显示报价窗口(只执行一次后取消订阅)。</summary>
private void OnCadIdleShowPalette(object sender, EventArgs e)
{
AcAp.Idle -= OnCadIdleShowPalette;
try
{
OpenForm3();
}
catch { }
}
public void Terminate()
{
try
{
if (_ps != null)
{
_ps.Visible = false;
_ps = null;
}
if (_form3 != null && !_form3.IsDisposed)
{
_form3.Dispose();
_form3 = null;
}
}
catch { }
}
#endregion
#region 命令
/// <summary>CADCJ 命令:打开/激活报价窗口(PaletteSet,可停靠)。</summary>
[CommandMethod("CADCJ", CommandFlags.Modal)]
public void OpenForm3()
{
try
{
// 已有 PaletteSet 则激活显示并重新停靠到左侧
if (_ps != null)
{
_ps.Visible = true;
try
{
_ps.DockEnabled = DockSides.Left;
_ps.Dock = DockSides.Left;
}
catch { }
return;
}
PluginLog("[CADCJ] OpenForm3 开始");
// 新建 Form3,转成子控件模式嵌入容器
_form3 = new Form3();
_form3.TopLevel = false;
_form3.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
_form3.Dock = System.Windows.Forms.DockStyle.Fill;
_form3.Visible = true;
PluginLog("[CADCJ] Form3 就绪");
// ★ 根治 ResyncToTheme 崩溃:PaletteSet 只加 UserControl 容器,
// 不直接加 Form(CAD 主题同步强改 Form.BackColor 会抛
// "控件不支持透明的背景色")。Form3 塞进 Panel 再加。
_hostPanel = new System.Windows.Forms.Panel();
_hostPanel.Dock = System.Windows.Forms.DockStyle.Fill;
_hostPanel.BackColor = System.Drawing.SystemColors.Control;
_hostPanel.Controls.Add(_form3);
// 新建 PaletteSet
_ps = new PaletteSet("扒图", new System.Guid("A3F2B5C1-7D8E-4A6B-9C0D-1E2F3A4B5C6D"));
PluginLog("[CADCJ] PaletteSet 创建成功");
_ps.Style = PaletteSetStyles.Snappable
| PaletteSetStyles.UsePaletteNameAsTitleForSingle;
_ps.Add("扒图", _hostPanel);
PluginLog("[CADCJ] Add 成功");
// ★ 启动时自动贴靠到 CAD 左侧,并设置足够尺寸
_ps.Size = new System.Drawing.Size(540, 800);
_ps.MinimumSize = new System.Drawing.Size(300, 400);
// ★ 先显示,再设置停靠(CAD PaletteSet 的特殊行为)
_ps.Visible = true;
PluginLog("[CADCJ] Visible=true 完成");
// ★ 启用左侧停靠 + 强制停靠到左侧
_ps.DockEnabled = DockSides.Left;
_ps.Dock = DockSides.Left;
PluginLog("[CADCJ] OpenForm3 全部完成 ✓");
}
catch (System.Exception ex)
{
PluginLog("[CADCJ] ⚠ 打开窗口失败: " + ex);
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc != null)
{
doc.Editor.WriteMessage("\n[CADCJ] 打开窗口失败: " + ex.Message);
}
}
}
/// <summary>插件级文件日志(写 cadcj 目录 diag.log,独立于 Form3)。</summary>
private static void PluginLog(string msg)
{
try
{
string dir = System.IO.Path.GetDirectoryName(
new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);
System.IO.File.AppendAllText(System.IO.Path.Combine(dir, "diag.log"),
DateTime.Now.ToString("HH:mm:ss.fff") + " " + msg + System.Environment.NewLine);
}
catch { }
}
// ============================================================
// 扒图号/扒箱号/扒元件 命令
// · 由 Form3 的按钮通过 SendStringToExecute 触发
// · 只允许框选 DBText/MText(过滤掉线条)
// · 选中文本用半透明颜色高亮
// · 选中的文本传回 Form3 插入到对应表格
// ============================================================
/// <summary>扒图号命令:CADPATU</summary>
[CommandMethod("CADPATU", CommandFlags.Modal)]
public void PaTuhaoCommand()
{
ExecutePaCommand(MyApp.PaMode.Tuhao);
}
/// <summary>扒箱号命令:CADPAXH</summary>
[CommandMethod("CADPAXH", CommandFlags.Modal)]
public void PaXianghaoCommand()
{
ExecutePaCommand(MyApp.PaMode.Xianghao);
}
/// <summary>扒元件命令:CADPAYJ</summary>
[CommandMethod("CADPAYJ", CommandFlags.Modal)]
public void PaYuanjianCommand()
{
ExecutePaCommand(MyApp.PaMode.Yuanjian);
}
/// <summary>清除所有高亮颜色命令:CADPACL</summary>
[CommandMethod("CADPACL", CommandFlags.Modal)]
public void PaClearCommand()
{
try
{
PaTextSelector.ClearAllHighlight();
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 已清除所有染色文本。");
}
catch (System.Exception ex)
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 清除失败: " + ex.Message);
}
}
/// <summary>执行扒数据命令的核心逻辑(连续框选模式)。</summary>
private void ExecutePaCommand(PaMode mode)
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc == null) return;
var ed = doc.Editor;
try
{
// 订阅事件:每次框选完一批文本,立即通过 Invoke 调用 Form3 的插入方法
PaTextSelector.BatchTextsPicked -= OnPaBatchTextsPicked;
PaTextSelector.BatchTextsPicked += OnPaBatchTextsPicked;
// 进入连续框选循环(直到用户按 ESC)
PaTextSelector.PickTextsContinuous(mode);
// 用户按 ESC 退出后,触发一次最终的"完成"提示(可选)
ed.WriteMessage("\n[扒数据] 已退出连续模式。");
// 取消订阅
PaTextSelector.BatchTextsPicked -= OnPaBatchTextsPicked;
}
catch (System.Exception ex)
{
ed.WriteMessage("\n[扒数据] 异常: " + ex.Message);
}
}
/// <summary>PaTextSelector 事件回调:把一批文本+框Handle传给 Form3 插入到表格。</summary>
private void OnPaBatchTextsPicked(PaMode mode, System.Collections.Generic.List<PaTextResult> results)
{
if (_form3 == null || _form3.IsDisposed) return;
try
{
_form3.Invoke(new System.Action(() =>
{
try { _form3.OnPaTextsPicked(mode, results); }
catch (System.Exception ex)
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 插入数据异常: " + ex.Message);
}
}));
}
catch { }
}
#endregion
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-34
View File
@@ -1,34 +0,0 @@
// ============================================================
// Form3 依赖清单
// 此文件记录窗体所使用的控件及其运行时依赖。
// ============================================================
// NuGet 包依赖:
// ----------------
// System.Data.SQLite.Core (版本 1.0.119.0)
// 安装命令: dotnet add package System.Data.SQLite.Core --version 1.0.119.0
// 或在 Visual Studio 中: 右键项目 → 管理 NuGet 包 → 搜索 System.Data.SQLite.Core
// DLL 文件依赖:
// ----------------
// 来自 未知:
// - AdvancedDataGridView.dll (托管 DLL)
// 来自 System.Data.SQLite.Core:
// - System.Data.SQLite.dll (托管 DLL)
// 编译说明:
// ----------------
// 1. 确保 NuGet 包已安装到项目
// 2. 编译时使用正确的 CPU 架构(x64 或 x86)
// 3. 运行时确保所有 DLL 文件与 exe 在同一目录
// 4. ★ 推荐用同目录下的 build.bat 一键编译(已自动配置 response file 和 manifest)
// manifest 的 DPI 策略与设计器一致(dpiAware=unaware),保证所见即所得
// 编译命令示例(x64):
// csc /target:winexe /platform:x64 /out:Form3.exe
// /win32manifest:app.manifest
// /r:System.Windows.Forms.dll /r:System.Drawing.dll
// /r:"AdvancedDataGridView.dll"
// /r:"System.Data.SQLite.dll"
// Form3.cs Form3.ui.cs
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-830
View File
@@ -1,830 +0,0 @@
// ============================================================
// 扒图号/扒箱号/扒元件 - CAD文本框选交互
// · 直接框选一次完成(无需点完成按钮)
// · 只框选 DBText/MText(线条自动过滤)
// · 不改文字颜色,而是在每个文字周围画彩色矩形框
// (图号=红色框, 箱号=绿色框, 元件=蓝色框)
// · 清除时删除所有彩色矩形框
// ============================================================
using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Colors;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace MyApp
{
/// <summary>
/// 扒数据模式:图号/箱号/元件
/// </summary>
public enum PaMode
{
Tuhao, // 扒图号
Xianghao, // 扒箱号
Yuanjian // 扒元件
}
/// <summary>
/// 扒图结果:一条文本 + 它对应的彩色框的 Handle(句柄字符串)
/// 用于关联表格数据行与 CAD 框实体,实现点击行定位、删除行删框。
/// ★ TextHandle:源文本实体自身的 Handle,用于判断"是否同一个文本"
/// (不同位置的相同内容文本 Handle 不同,不算重复)。
/// </summary>
public class PaTextResult
{
public string Text;
public string FrameHandle;
public string TextHandle = "";
}
/// <summary>
/// CAD 文本框选交互:框选一次即完成,在文字周围画彩色矩形框(不改文字颜色)。
/// </summary>
public static class PaTextSelector
{
// 三种模式对应不同的矩形框颜色(ACI:3=绿,4=青,1=红)
private const short TuhaoColorIndex = 3; // 图号=绿
private const short XianghaoColorIndex = 4; // 箱号=青
private const short YuanjianColorIndex = 1; // 元件=红
// 矩形框图层名(便于批量清除)
public const string PaLayerName = "__CADCJ_PA_FRAME";
/// <summary>
/// 连续扒数据事件:每次框选完成(松开鼠标)就触发一次,把这一批文本+框Handle送给调用方。
/// 调用方在 Form3 里把数据插入到表格,然后控制流回到 PickTexts 继续下一次框选。
/// </summary>
public static event System.Action<PaMode, List<PaTextResult>> BatchTextsPicked;
/// <summary>
/// 连续框选模式:用户点一次按钮进入,可以连续框选多次,每次框选立即送出一批文本。
/// 按回车/空格完成当前批次,ESC 退出连续模式。
/// 方向决定行为:
/// · 左上→右下(正向框选):每个文本一条记录
/// · 右下→左上(反向框选,CAD里称为"交叉框选"):多条文本合并为一条
/// </summary>
/// <param name="mode">扒数据模式(决定矩形框颜色)</param>
public static void PickTextsContinuous(PaMode mode)
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc == null) return;
var ed = doc.Editor;
// ★ 强制开启透明度显示(TRANSPARENCYDISPLAY=1)
// 否则 Hatch.Transparency 在某些电脑上不生效,蒙版显示为不透明
try { AcAp.SetSystemVariable("TRANSPARENCYDISPLAY", 1); } catch { }
// ★ 当前模式(允许右键切换,所以用变量保存当前模式)
PaMode currentMode = mode;
try
{
var typeValues = new TypedValue[]
{
new TypedValue(-4, "<OR"),
new TypedValue((int)DxfCode.Start, "TEXT"),
new TypedValue((int)DxfCode.Start, "MTEXT"),
new TypedValue(-4, "OR>")
};
var filter = new SelectionFilter(typeValues);
// ★ 连续循环:每次框选完立即触发事件,直到用户按 ESC
while (true)
{
// 根据当前模式获取颜色和名称
short colorIndex;
string modeName;
switch (currentMode)
{
case PaMode.Tuhao: colorIndex = TuhaoColorIndex; modeName = "图号"; break;
case PaMode.Xianghao: colorIndex = XianghaoColorIndex; modeName = "箱号"; break;
default: colorIndex = YuanjianColorIndex; modeName = "元件"; break;
}
// 第一角点
// ★ AllowNone=true:右键会返回 None,用来切换模式;ESC 返回 Cancel 退出
var po1 = new PromptPointOptions("\n框选【" + modeName + "】起点(右键切换模式,ESC结束): ");
po1.AllowNone = true;
var pres1 = ed.GetPoint(po1);
if (pres1.Status == PromptStatus.Cancel) break; // ESC 退出
if (pres1.Status == PromptStatus.None)
{
// ★ 右键:切换到下一个模式(图号→箱号→元件→退出)
PaMode next = GetNextMode(currentMode);
if (next == currentMode)
{
// 元件模式右键 → 退出
ed.WriteMessage("\n[扒数据] 已退出连续模式。");
break;
}
currentMode = next;
ed.WriteMessage("\n[扒数据] 切换到【" + GetModeName(currentMode) + "】模式。");
continue;
}
if (pres1.Status != PromptStatus.OK) break;
Point3d pt1 = pres1.Value;
// 对角点
// ★ AllowNone=true:右键也允许切换模式(回到第一角点重新开始)
var co = new PromptCornerOptions("\n对角点: ", pt1);
co.AllowNone = true;
var cres = ed.GetCorner(co);
if (cres.Status == PromptStatus.Cancel) break; // ESC 退出
if (cres.Status == PromptStatus.None)
{
// ★ 右键:切换到下一个模式,回到第一角点
PaMode next = GetNextMode(currentMode);
if (next == currentMode)
{
ed.WriteMessage("\n[扒数据] 已退出连续模式。");
break;
}
currentMode = next;
ed.WriteMessage("\n[扒数据] 切换到【" + GetModeName(currentMode) + "】模式。");
continue;
}
if (cres.Status != PromptStatus.OK) break;
Point3d pt2 = cres.Value;
// ★ 关键:判断方向(任意一项反向即为"交叉框选"=合并模式)
// pt1.X > pt2.X = 从右往左框选(pt1 在 pt2 右边)
// pt1.Y < pt2.Y = 从下往上框选(pt1 在 pt2 下方)
// 任一条件满足都视为反向框选 → 多文本合并为一条
bool isCrossing = (pt1.X > pt2.X) || (pt1.Y < pt2.Y);
double minX = Math.Min(pt1.X, pt2.X);
double maxX = Math.Max(pt1.X, pt2.X);
double minY = Math.Min(pt1.Y, pt2.Y);
double maxY = Math.Max(pt1.Y, pt2.Y);
Point3d minPt = new Point3d(minX, minY, 0);
Point3d maxPt = new Point3d(maxX, maxY, 0);
// ★ 统一用交叉窗口选择:只要框碰到文字(部分重叠)即选中,
// 不再要求把文字完全框住(旧版正向框选用 SelectWindow 必须全包,漏选严重)。
// 框选方向只决定业务模式(正向=逐条,反向=合并),不再影响选择方式。
PromptSelectionResult res = ed.SelectCrossingWindow(minPt, maxPt, filter);
if (res.Status != PromptStatus.OK) continue; // 这一次没选中,继续下一次
ObjectId[] ids = res.Value.GetObjectIds();
if (ids.Length == 0) continue;
// 收集文本
var items = new List<TextItem>();
using (var tr = doc.Database.TransactionManager.StartTransaction())
{
foreach (ObjectId id in ids)
{
var ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
if (ent == null) continue;
string text = "";
Point3d pos = Point3d.Origin;
Extents3d? bounds = null;
var dt = ent as DBText;
var mt = ent as MText;
if (dt != null)
{
text = dt.TextString;
try
{
// ★ 用 CAD 自身的 GeometricExtents 获取文本框边界
// 宽度通常准确,高度包含字体预留空间偏大
// 所以高度用字高重新估算,宽度用 GeometricExtents
bounds = dt.GeometricExtents;
if (bounds.HasValue)
{
double h = dt.Height;
if (h > 0)
{
// ★ 宽度:直接用 GeometricExtents 的宽度(CAD 自身文本框宽度)
double left = bounds.Value.MinPoint.X;
double right = bounds.Value.MaxPoint.X;
// ★ 高度:用字高紧凑估算(底部=baseline下0.2h,顶部=baseline上1.0h)
double bottom = dt.Position.Y - h * 0.2;
double top = dt.Position.Y + h * 1.0;
bounds = new Extents3d(
new Point3d(left, bottom, 0),
new Point3d(right, top, 0));
}
}
}
catch { }
// ★ 用文字中心点作为排序基准
if (bounds.HasValue)
pos = new Point3d(
(bounds.Value.MinPoint.X + bounds.Value.MaxPoint.X) / 2.0,
(bounds.Value.MinPoint.Y + bounds.Value.MaxPoint.Y) / 2.0,
0);
else
pos = dt.Position;
}
else if (mt != null)
{
text = mt.Text;
try { bounds = mt.GeometricExtents; } catch { }
if (bounds.HasValue)
pos = new Point3d(
(bounds.Value.MinPoint.X + bounds.Value.MaxPoint.X) / 2.0,
(bounds.Value.MinPoint.Y + bounds.Value.MaxPoint.Y) / 2.0,
0);
else
pos = mt.Location;
}
if (!string.IsNullOrEmpty(text))
{
items.Add(new TextItem
{
Text = text.Trim(),
Position = pos,
Bounds = bounds,
ObjectId = id,
TextHandle = ent.Handle.ToString()
});
}
}
tr.Commit();
}
if (items.Count == 0) continue;
// ★ 按列分组排序:先从左到右分列,列内从上到下
// 用户需求示例:1在上 2在下(左列) 3在上 4在下(右列)
// 期望顺序:1、2、3、4(先左列从上到下,再右列从上到下)
// 算法:
// 1. 按X左边界升序
// 2. 扫描分列:X范围有重叠的归为同一列(垂直方向对齐的文字)
// 3. 每列内按Y降序(上在前)
// 4. 列间按X升序(左在前)合并
{
System.Func<TextItem, double> getLeft = it =>
it.Bounds.HasValue ? it.Bounds.Value.MinPoint.X : it.Position.X;
System.Func<TextItem, double> getRight = it =>
it.Bounds.HasValue ? it.Bounds.Value.MaxPoint.X : it.Position.X;
System.Func<TextItem, double> getCenterY = it =>
it.Bounds.HasValue ? (it.Bounds.Value.MinPoint.Y + it.Bounds.Value.MaxPoint.Y) / 2.0 : it.Position.Y;
// 1. 按X左边界升序
items.Sort((a, b) => getLeft(a).CompareTo(getLeft(b)));
// 2. 扫描分列:X范围有重叠的归为同一列
var columns = new List<List<TextItem>>();
double curMaxRight = double.NegativeInfinity;
List<TextItem> curCol = null;
foreach (var it in items)
{
double left = getLeft(it);
double right = getRight(it);
if (curCol == null || left > curMaxRight)
{
// 新列
curCol = new List<TextItem>();
columns.Add(curCol);
curMaxRight = right;
}
else
{
// 加入当前列,更新右边界
if (right > curMaxRight) curMaxRight = right;
}
curCol.Add(it);
}
// 3. 每列内按Y降序(上在前)
foreach (var col in columns)
{
col.Sort((a, b) => getCenterY(b).CompareTo(getCenterY(a)));
}
// 4. 合并(列间已按X升序)
items.Clear();
foreach (var col in columns) items.AddRange(col);
}
var result = new List<PaTextResult>();
if (isCrossing && items.Count > 1)
{
// ★ 反向框选 + 多条文本:合并模式
// 画一个大框,所有文本共用这个框Handle
// 每个文本作为独立的 PaTextResult 传出(共用同一个框Handle),
// 让 Form3 能检查每个文本是否已存在并自动合并已存在的元件
string mergedHandle = DrawMergedFrame(items, colorIndex);
foreach (var it in items)
{
if (!string.IsNullOrEmpty(it.Text))
{
result.Add(new PaTextResult
{
Text = it.Text.Trim(),
FrameHandle = mergedHandle,
TextHandle = it.TextHandle
});
}
}
}
else if (currentMode == PaMode.Yuanjian)
{
// 元件模式(正向框选或单条):每个文字一条,每个文字一个框
var handles = DrawTextFrames(items, colorIndex);
for (int i = 0; i < items.Count; i++)
{
string h = i < handles.Count ? handles[i] : "";
result.Add(new PaTextResult
{
Text = items[i].Text,
FrameHandle = h,
TextHandle = items[i].TextHandle
});
}
}
else
{
// 图号/箱号(正向框选或单条):去重(同名只算一条),框对应
var seen = new HashSet<string>();
var seenTextHandles = new HashSet<string>();
var handles = DrawTextFrames(items, colorIndex);
for (int i = 0; i < items.Count; i++)
{
// ★ 用文本实体Handle去重(同一个文本实体只算一条),
// 不同位置的相同内容文本算两条
if (seenTextHandles.Add(items[i].TextHandle) && seen.Add(items[i].Text))
{
string h = i < handles.Count ? handles[i] : "";
result.Add(new PaTextResult
{
Text = items[i].Text,
FrameHandle = h,
TextHandle = items[i].TextHandle
});
}
}
}
// ★ 立即把这一批数据(文本+框Handle)送给调用方(插入到表格)
if (result.Count > 0)
{
var handler = BatchTextsPicked;
if (handler != null)
{
try { handler(currentMode, result); } catch { }
}
// ★ 扒完一批后自动切换到下一个模式(图号→箱号→元件)
// 元件模式扒完后保持元件模式不变(继续扒下一个箱号的元件)
if (currentMode == PaMode.Tuhao)
{
currentMode = PaMode.Xianghao;
ed.WriteMessage("\n[扒数据] 图号已扒完,自动切换到【箱号】模式。");
}
else if (currentMode == PaMode.Xianghao)
{
currentMode = PaMode.Yuanjian;
ed.WriteMessage("\n[扒数据] 箱号已扒完,自动切换到【元件】模式。");
}
}
// 继续下一次框选
}
}
catch (System.Exception ex)
{
try { ed.WriteMessage("\n[扒数据] 异常: " + ex.Message); } catch { }
}
}
/// <summary>
/// 获取右键切换的下一个扒图模式。
/// 顺序:图号 → 箱号 → 元件 → 退出(返回当前模式表示退出)。
/// </summary>
private static PaMode GetNextMode(PaMode current)
{
switch (current)
{
case PaMode.Tuhao: return PaMode.Xianghao;
case PaMode.Xianghao: return PaMode.Yuanjian;
default: return PaMode.Yuanjian; // 元件右键 → 返回自身,外层判断退出
}
}
/// <summary>获取模式的中文名称(用于切换提示)。</summary>
private static string GetModeName(PaMode mode)
{
switch (mode)
{
case PaMode.Tuhao: return "图号";
case PaMode.Xianghao: return "箱号";
default: return "元件";
}
}
/// <summary>
/// 反向框选合并时:计算所有文字的总边界,画一个大框包住所有文字。
/// 返回:大框的 Handle 字符串(失败返回空字符串)。
/// </summary>
private static string DrawMergedFrame(List<TextItem> items, short colorIndex)
{
string handle = "";
try
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc == null) return handle;
var db = doc.Database;
// 先计算所有文字的合并 Extents
double? minX = null, minY = null, maxX = null, maxY = null;
foreach (var item in items)
{
if (item.Bounds == null) continue;
Extents3d ext = item.Bounds.Value;
if (minX == null || ext.MinPoint.X < minX.Value) minX = ext.MinPoint.X;
if (minY == null || ext.MinPoint.Y < minY.Value) minY = ext.MinPoint.Y;
if (maxX == null || ext.MaxPoint.X > maxX.Value) maxX = ext.MaxPoint.X;
if (maxY == null || ext.MaxPoint.Y > maxY.Value) maxY = ext.MaxPoint.Y;
}
if (minX == null) return handle;
using (var tr = db.TransactionManager.StartTransaction())
{
// 确保专用图层存在
LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
ObjectId layerId;
if (lt.Has(PaLayerName))
{
layerId = lt[PaLayerName];
}
else
{
lt.UpgradeOpen();
var layerDef = new LayerTableRecord { Name = PaLayerName };
layerId = lt.Add(layerDef);
tr.AddNewlyCreatedDBObject(layerDef, true);
}
var ms = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
// ★ 先删除这批文字之前已有的旧框(避免小框和大框同时存在)
// 遍历当前空间,找出 __CADCJ_PA_FRAME 图层上与这批文字 Bounds 相交的实体,
// 通过 EraseGroupForEntity 删除整个组(边框+蒙版一起删)
var idsToDelete = new List<ObjectId>();
foreach (ObjectId entId in ms)
{
var ent = tr.GetObject(entId, OpenMode.ForRead, false, true) as Entity;
if (ent == null) continue;
if (ent.LayerId != layerId) continue;
if (ent.IsErased) continue;
Extents3d? entExt = null;
try { entExt = ent.GeometricExtents; } catch { }
if (!entExt.HasValue) continue;
// 检查是否与任何文字 item 的 Bounds 相交
foreach (var item in items)
{
if (item.Bounds == null) continue;
if (BoundsIntersect(entExt.Value, item.Bounds.Value))
{
idsToDelete.Add(entId);
break;
}
}
}
foreach (ObjectId id in idsToDelete)
{
// ★ 先删除同组的其他实体(Hatch),再删除主实体
EraseGroupForEntity(tr, id);
var ent = tr.GetObject(id, OpenMode.ForWrite);
if (!ent.IsErased) ent.Erase();
}
// ★ 边距极小:总宽高的 2%,最小 0.5
double totalW = maxX.Value - minX.Value;
double totalH = maxY.Value - minY.Value;
double padX = Math.Max(totalW * 0.02, 0.5);
double padY = Math.Max(totalH * 0.02, 0.5);
// 大框四角点(带边距,X和Y方向各自按比例)
Point3d p1 = new Point3d(minX.Value - padX, minY.Value - padY, 0);
Point3d p2 = new Point3d(maxX.Value + padX, minY.Value - padY, 0);
Point3d p3 = new Point3d(maxX.Value + padX, maxY.Value + padY, 0);
Point3d p4 = new Point3d(minX.Value - padX, maxY.Value + padY, 0);
var pl = new Polyline();
pl.AddVertexAt(0, new Point2d(p1.X, p1.Y), 0, 0, 0);
pl.AddVertexAt(1, new Point2d(p2.X, p2.Y), 0, 0, 0);
pl.AddVertexAt(2, new Point2d(p3.X, p3.Y), 0, 0, 0);
pl.AddVertexAt(3, new Point2d(p4.X, p4.Y), 0, 0, 0);
pl.Closed = true;
pl.Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex);
pl.LayerId = layerId;
pl.LineWeight = LineWeight.LineWeight070;
ms.AppendEntity(pl);
tr.AddNewlyCreatedDBObject(pl, true);
// ★ 记录大框的 Handle
handle = pl.Handle.ToString();
// ★ 添加半透明填充蒙版(用 Hatch 实体,支持透明度)
var hatch = new Hatch();
hatch.SetHatchPattern(HatchPatternType.PreDefined, "SOLID");
hatch.Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex);
hatch.Transparency = new Transparency(65); // 65% 透明度
hatch.LayerId = layerId;
ms.AppendEntity(hatch);
tr.AddNewlyCreatedDBObject(hatch, true);
ObjectIdCollection hatchLoopIds = new ObjectIdCollection();
hatchLoopIds.Add(pl.Id);
hatch.AppendLoop(HatchLoopTypes.Default, hatchLoopIds);
// ★ 把 Polyline 和 Hatch 创建为一个组(整体选中/整体删除)
MakeFrameGroup(db, tr, pl.Id, hatch.Id);
tr.Commit();
}
doc.Editor.UpdateScreen();
doc.Editor.Regen();
}
catch (Exception ex)
{
try
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 画合并框失败: " + ex.Message);
}
catch { }
}
return handle;
}
/// <summary>
/// 检查两个 Extents3d 是否相交(用于删除旧框时判断范围重叠)。
/// </summary>
private static bool BoundsIntersect(Extents3d a, Extents3d b)
{
// X 方向不相交
if (a.MaxPoint.X < b.MinPoint.X || a.MinPoint.X > b.MaxPoint.X) return false;
// Y 方向不相交
if (a.MaxPoint.Y < b.MinPoint.Y || a.MinPoint.Y > b.MaxPoint.Y) return false;
return true;
}
/// <summary>
/// ★ 把 Polyline(边框) 和 Hatch(蒙版) 创建为一个命名组,
/// 这样用户在 CAD 里选中/删除其中一个时,整个组(边框+蒙版)会一起被选中/删除。
/// </summary>
private static void MakeFrameGroup(Database db, Transaction tr, ObjectId plId, ObjectId hatchId)
{
try
{
var groupDict = (DBDictionary)tr.GetObject(db.GroupDictionaryId, OpenMode.ForWrite);
// 组名用 Polyline 的 Handle 保证唯一
string groupName = "CADCJ_PA_FRAME_" + plId.Handle.ToString();
var group = new Group(groupName, true); // true = 可选中
group.Append(new ObjectIdCollection(new[] { plId, hatchId }));
groupDict.SetAt(groupName, group);
tr.AddNewlyCreatedDBObject(group, true);
}
catch { }
}
/// <summary>
/// ★ 删除包含指定实体的所有 Group 内的所有实体(连同 Group 本身一起删除)。
/// 用于"删除框时自动删除关联的蒙版"。
/// </summary>
public static void EraseGroupForEntity(Transaction tr, ObjectId entId)
{
try
{
var ent = tr.GetObject(entId, OpenMode.ForRead) as Entity;
if (ent == null) return;
// 获取实体的所有 PersistentReactor(Group 会作为 reactor 记录)
ObjectIdCollection reactors = ent.GetPersistentReactorIds();
var idsToErase = new List<ObjectId>();
var groupsToErase = new List<ObjectId>();
foreach (ObjectId reactorId in reactors)
{
var grp = tr.GetObject(reactorId, OpenMode.ForRead) as Group;
if (grp == null) continue;
// 收集 Group 内所有实体
foreach (ObjectId memberId in grp.GetAllEntityIds())
{
if (!idsToErase.Contains(memberId)) idsToErase.Add(memberId);
}
groupsToErase.Add(reactorId);
}
// 删除 Group 内所有实体
foreach (ObjectId memberId in idsToErase)
{
if (memberId == entId) continue; // 主实体由调用方删除
try
{
var member = tr.GetObject(memberId, OpenMode.ForWrite);
if (!member.IsErased) member.Erase();
}
catch { }
}
// 删除 Group 本身
foreach (ObjectId groupId in groupsToErase)
{
try
{
var grp = tr.GetObject(groupId, OpenMode.ForWrite);
if (!grp.IsErased) grp.Erase();
}
catch { }
}
}
catch { }
}
/// <summary>
/// 在每个文字周围画一个彩色矩形框(LWPolyline),不改文字本身的颜色。
/// 所有矩形框放在专用图层 __CADCJ_PA_FRAME 上,方便批量清除。
/// 返回:每个 item 对应的框 Handle 字符串列表(和 items 顺序一致;无 Bounds 的为空字符串)。
/// </summary>
private static List<string> DrawTextFrames(List<TextItem> items, short colorIndex)
{
var handles = new List<string>();
try
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc == null) return handles;
var db = doc.Database;
using (var tr = db.TransactionManager.StartTransaction())
{
// 确保专用图层存在(如果不存在就创建)
LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
ObjectId layerId;
if (lt.Has(PaLayerName))
{
layerId = lt[PaLayerName];
}
else
{
lt.UpgradeOpen();
var layerDef = new LayerTableRecord { Name = PaLayerName };
layerId = lt.Add(layerDef);
tr.AddNewlyCreatedDBObject(layerDef, true);
}
// 获取当前空间(模型空间或图纸空间)
var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
var ms = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
foreach (var item in items)
{
if (item.Bounds == null) { handles.Add(""); continue; }
Extents3d ext = item.Bounds.Value;
// ★ 用文字的实际位置和高度估算更紧凑的范围
// GeometricExtents 可能包含字体预留的 ascent/descent 空间,
// 这里用文字中心点和估算的宽高来定义框,使其更贴合文字
double textW, textH;
if (ext.MaxPoint.Y - ext.MinPoint.Y > ext.MaxPoint.X - ext.MinPoint.X * 3)
{
// 如果高度远大于宽度(多行或特殊情况),用 GeometricExtents
textW = ext.MaxPoint.X - ext.MinPoint.X;
textH = ext.MaxPoint.Y - ext.MinPoint.Y;
}
else
{
// 单行文字:用中心点和估算尺寸
textW = ext.MaxPoint.X - ext.MinPoint.X;
textH = ext.MaxPoint.Y - ext.MinPoint.Y;
}
// ★ 边距极小:文字宽高的 3%,最小 0.3
double padX = Math.Max(textW * 0.03, 0.3);
double padY = Math.Max(textH * 0.03, 0.3);
// 矩形四角点(带极小边距)
Point3d p1 = new Point3d(ext.MinPoint.X - padX, ext.MinPoint.Y - padY, 0);
Point3d p2 = new Point3d(ext.MaxPoint.X + padX, ext.MinPoint.Y - padY, 0);
Point3d p3 = new Point3d(ext.MaxPoint.X + padX, ext.MaxPoint.Y + padY, 0);
Point3d p4 = new Point3d(ext.MinPoint.X - padX, ext.MaxPoint.Y + padY, 0);
// 创建 LWPolyline 矩形
var pl = new Polyline();
pl.AddVertexAt(0, new Point2d(p1.X, p1.Y), 0, 0, 0);
pl.AddVertexAt(1, new Point2d(p2.X, p2.Y), 0, 0, 0);
pl.AddVertexAt(2, new Point2d(p3.X, p3.Y), 0, 0, 0);
pl.AddVertexAt(3, new Point2d(p4.X, p4.Y), 0, 0, 0);
pl.Closed = true;
// 设置颜色和图层
pl.Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex);
pl.LayerId = layerId;
// 线宽更粗,看得清
pl.LineWeight = LineWeight.LineWeight070;
ms.AppendEntity(pl);
tr.AddNewlyCreatedDBObject(pl, true);
// ★ 记录框的 Handle,用于关联表格数据行
handles.Add(pl.Handle.ToString());
// ★ 添加半透明填充蒙版(用 Hatch 实体,支持透明度)
var hatch = new Hatch();
hatch.SetHatchPattern(HatchPatternType.PreDefined, "SOLID");
hatch.Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex);
hatch.Transparency = new Transparency(65); // 65% 透明度
hatch.LayerId = layerId;
ms.AppendEntity(hatch);
tr.AddNewlyCreatedDBObject(hatch, true);
ObjectIdCollection hatchLoopIds = new ObjectIdCollection();
hatchLoopIds.Add(pl.Id);
hatch.AppendLoop(HatchLoopTypes.Default, hatchLoopIds);
// ★ 把 Polyline 和 Hatch 创建为一个组(整体选中/整体删除)
MakeFrameGroup(db, tr, pl.Id, hatch.Id);
}
tr.Commit();
}
// 刷新显示
doc.Editor.UpdateScreen();
doc.Editor.Regen();
}
catch (Exception ex)
{
try
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 画框失败: " + ex.Message);
}
catch { }
}
return handles;
}
/// <summary>
/// 清除所有扒数据时画的彩色矩形框(删除 __CADCJ_PA_FRAME 图层上的所有对象)。
/// 不动文字本身,文字保持原色。
/// </summary>
public static void ClearAllHighlight()
{
try
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc == null) return;
var db = doc.Database;
using (var tr = db.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
// 遍历所有块定义(模型空间+所有布局),删除目标图层上的对象
foreach (ObjectId btrId in bt)
{
var btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);
var ids = new List<ObjectId>();
foreach (ObjectId entId in btr)
{
var ent = tr.GetObject(entId, OpenMode.ForRead, false, true) as Entity;
if (ent == null) continue;
if (ent.Layer == PaLayerName)
{
ids.Add(entId);
}
}
if (ids.Count > 0)
{
btr.UpgradeOpen();
foreach (ObjectId id in ids)
{
// ★ 先删除同组的其他实体,再删除主实体
EraseGroupForEntity(tr, id);
var ent = tr.GetObject(id, OpenMode.ForWrite);
if (!ent.IsErased) ent.Erase();
}
}
}
tr.Commit();
}
doc.Editor.UpdateScreen();
doc.Editor.Regen();
try { doc.Editor.WriteMessage("\n[扒数据] 已清除所有标记框。"); } catch { }
}
catch (Exception ex)
{
try
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 清除失败: " + ex.Message);
}
catch { }
}
}
private class TextItem
{
public string Text;
public Point3d Position;
public Extents3d? Bounds;
public ObjectId ObjectId;
public string TextHandle = "";
}
}
}
Binary file not shown.
-29
View File
@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10/11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">unaware</dpiAwareness>
</windowsSettings>
</application>
</assembly>
-19
View File
@@ -1,19 +0,0 @@
@echo off
REM ============================================
REM Auto-generated build script
REM All non-ASCII paths are in build.rsp (UTF-8)
REM Keep this .bat file ASCII-only to avoid cmd codepage issues
REM ============================================
cd /d "%~dp0"
"%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\csc.exe" @build.rsp
if %ERRORLEVEL% EQU 0 (
echo Build OK. Launching...
powershell -NoProfile -Command "Start-Process -FilePath ('%~dp0' + (Select-String -Path build.rsp -Pattern '^/out:(.+)$').Matches.Groups[1].Value)"
) else (
echo Build FAILED - see messages above
pause
)
-27
View File
@@ -1,27 +0,0 @@
# Auto-generated csc response file
/target:library
/platform:x64
/utf8output
/out:cadcj.dll
/win32manifest:app.manifest
/r:System.Windows.Forms.dll
/r:System.Drawing.dll
/r:System.dll
/r:System.Data.dll
/r:System.Core.dll
/r:System.Xml.dll
/r:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\PresentationCore.dll"
/r:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\WindowsBase.dll"
/r:System.IO.Compression.dll
/r:System.IO.Compression.FileSystem.dll
/r:"AdvancedDataGridView.dll"
/r:"System.Data.SQLite.dll"
/r:"E:\cad2\AutoCAD 2018\acdbmgd.dll"
/r:"E:\cad2\AutoCAD 2018\acmgd.dll"
/r:"E:\cad2\AutoCAD 2018\accoremgd.dll"
CadPlugin.cs
Form3.cs
Form3.ui.cs
PaTextSelector.cs
新建项目.cs
新建项目.ui.cs
-25
View File
@@ -1,25 +0,0 @@
/target:library
/platform:x64
/utf8output
/out:cadcj_v2.dll
/r:System.Windows.Forms.dll
/r:System.Drawing.dll
/r:System.dll
/r:System.Data.dll
/r:System.Core.dll
/r:System.Xml.dll
/r:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\PresentationCore.dll"
/r:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\WindowsBase.dll"
/r:System.IO.Compression.dll
/r:System.IO.Compression.FileSystem.dll
/r:"AdvancedDataGridView.dll"
/r:"System.Data.SQLite.dll"
/r:"D:\ProgramData\cad\AutoCAD 2018\acdbmgd.dll"
/r:"D:\ProgramData\cad\AutoCAD 2018\acmgd.dll"
/r:"D:\ProgramData\cad\AutoCAD 2018\accoremgd.dll"
CadPlugin.cs
Form3.cs
Form3.ui.cs
PaTextSelector.cs
新建项目.cs
新建项目.ui.cs
Binary file not shown.
-7
View File
@@ -1,7 +0,0 @@
{
"ApiKey": "sk-65b3963488ab420aa9df3e4dafa02768",
"BaseUrl": "https://api.deepseek.com",
"Model": "deepseek-v4-flash",
"Enabled": false,
"WebSearch": true
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
-26
View File
@@ -1,26 +0,0 @@
@echo off
chcp 936 >nul
title 成套报价 CAD 插件卸载程序
REM 切换到批处理文件所在目录(支持从任意位置运行)
cd /d "%~dp0"
REM 检查 PowerShell 脚本是否存在
if not exist "卸载CAD插件.ps1" (
echo [错误] 未找到 卸载CAD插件.ps1
echo 请确保本批处理文件与 卸载CAD插件.ps1 在同一目录。
pause
exit /b 1
)
REM 以管理员身份运行 PowerShell 脚本(避免 HKLM 删除提权弹窗中断)
powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process powershell -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','%~dp0卸载CAD插件.ps1' -Verb RunAs -Wait"
REM 若用户取消提权,则非提权运行(HKLM 删除会自动提权,acaddoc.lsp 和 TRUSTEDPATHS 无需管理员)
if errorlevel 1 (
echo.
echo [提示] 管理员提权被取消,尝试非提权运行...
powershell -NoProfile -ExecutionPolicy Bypass -File "卸载CAD插件.ps1"
)
pause
-263
View File
@@ -1,263 +0,0 @@
# ===========================================================================
# 成套报价 CAD 插件 - 通用卸载脚本
# 自动检测 AutoCAD 并移除所有安装时写入的配置
# 用法:以管理员身份运行,或在 PowerShell 中执行本脚本
# ===========================================================================
# --- 0. 环境与自检 ---
$ErrorActionPreference = 'Stop'
# $PSScriptRoot 在 -File 模式下可靠返回脚本所在目录(PS 3.0+)
$scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }
$scriptDir = $scriptDir.TrimEnd('\') # 统一去除尾部反斜杠,便于比较
# 检测是否管理员(写 HKLM 需要)
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "[提示] 当前未以管理员身份运行,HKLM 注册表删除将自动提权。" -ForegroundColor Yellow
Write-Host " acaddoc.lsp 和 TRUSTEDPATHS 无需管理员权限。" -ForegroundColor Yellow
Write-Host ""
}
Write-Host "======================================================" -ForegroundColor Cyan
Write-Host " 成套报价 CAD 插件卸载程序" -ForegroundColor Cyan
Write-Host " 插件目录: $scriptDir" -ForegroundColor Cyan
Write-Host "======================================================" -ForegroundColor Cyan
Write-Host ""
# --- 1. 检测已安装的 AutoCAD 版本 ---
Write-Host "[1/4] 检测 AutoCAD 安装..." -ForegroundColor Green
$acadInstalls = @()
$regRoots = @(
'HKLM:\SOFTWARE\Autodesk\AutoCAD',
'HKLM:\SOFTWARE\WOW6432Node\Autodesk\AutoCAD'
)
foreach ($root in $regRoots) {
if (-not (Test-Path $root)) { continue }
Get-ChildItem $root -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^R\d+\.0$' } | ForEach-Object {
$verKey = $_.PSPath
$verNum = $_.PSChildName
Get-ChildItem $verKey -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^ACAD-\d+:\d+$' } | ForEach-Object {
$langKey = $_.PSPath
$props = Get-ItemProperty -Path $langKey -ErrorAction SilentlyContinue
$loc = $props.AcadLocation
$prod = $props.ProductName
if ($loc -and (Test-Path $loc)) {
$acadInstalls += [PSCustomObject]@{
Version = $verNum
LangKey = $_.PSChildName
Location = $loc
Product = $prod
HKLMKey = $langKey
}
}
}
}
}
if ($acadInstalls.Count -eq 0) {
Write-Host "[警告] 未检测到已安装的 AutoCAD,无法清理注册表。" -ForegroundColor Yellow
Write-Host " 如有手动残留的 acaddoc.lsp,请手动检查。" -ForegroundColor Yellow
if (-not $env:CADCJ_SILENT) { Read-Host "按回车退出" }
exit 0
}
Write-Host "找到 $($acadInstalls.Count) 个 AutoCAD 安装:" -ForegroundColor Green
for ($i = 0; $i -lt $acadInstalls.Count; $i++) {
$a = $acadInstalls[$i]
Write-Host (" [{0}] {1} ({2}) - {3}" -f $i, $a.Product, $a.Version, $a.Location) -ForegroundColor White
}
Write-Host ""
# 若有多个,让用户选择
$target = $acadInstalls[0]
if ($acadInstalls.Count -gt 1) {
if ($env:CADCJ_SILENT) {
Write-Host "[静默模式] 检测到多个 AutoCAD,默认选择第一个: $($target.Product)" -ForegroundColor Yellow
} else {
do {
$sel = Read-Host "请选择要卸载的 AutoCAD 序号 (0-$($acadInstalls.Count - 1)),默认 0"
if ([string]::IsNullOrWhiteSpace($sel)) { $sel = '0' }
} until ($sel -match '^\d+$' -and [int]$sel -lt $acadInstalls.Count)
$target = $acadInstalls[[int]$sel]
}
}
Write-Host ""
Write-Host ("目标: {0} ({1})" -f $target.Product, $target.Version) -ForegroundColor Cyan
Write-Host ""
# --- 2. 删除 HKLM 注册表 CADCJ 节点 ---
Write-Host "[2/4] 删除 HKLM 自动加载注册表..." -ForegroundColor Green
$hklmPath = $target.HKLMKey -replace '^HKLM:\\', ''
$appsPath = "HKLM:\$hklmPath\Apps\CADCJ"
if (-not (Test-Path $appsPath)) {
Write-Host " HKLM 中无 CADCJ 节点,跳过" -ForegroundColor DarkGray
} else {
if ($isAdmin) {
Remove-Item -Path $appsPath -Recurse -Force -ErrorAction SilentlyContinue
if (-not (Test-Path $appsPath)) {
Write-Host " 已删除 HKLM 注册表节点" -ForegroundColor Green
} else {
Write-Host " [警告] 删除失败,请检查权限" -ForegroundColor Yellow
}
} else {
# 提权删除
$tmpPs1 = Join-Path $env:TEMP "cadcj_uninstall_hklm.ps1"
$tmpContent = @"
`$ErrorActionPreference = 'Stop'
`$path = '$appsPath'
if (Test-Path `$path) { Remove-Item -Path `$path -Recurse -Force }
if (-not (Test-Path `$path)) { Write-Host ' HKLM 注册表节点已删除' } else { Write-Host ' [警告] 删除失败' }
"@
$tmpContent | Out-File -FilePath $tmpPs1 -Encoding UTF8 -Force
$p = Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile","-ExecutionPolicy","Bypass","-File",$tmpPs1 -Verb RunAs -Wait -PassThru
if ($p.ExitCode -eq 0) {
Write-Host " 已删除 HKLM 注册表节点" -ForegroundColor Green
} else {
Write-Host " [警告] HKLM 删除失败(用户取消提权?)" -ForegroundColor Yellow
}
Remove-Item $tmpPs1 -Force -ErrorAction SilentlyContinue
}
}
Write-Host ""
# --- 3. 从所有 TRUSTEDPATHS 移除插件目录 ---
Write-Host "[3/4] 移除受信任路径(TRUSTEDPATHS)..." -ForegroundColor Green
$hkcuRoot = "HKCU:\SOFTWARE\Autodesk\AutoCAD\$($target.Version)\$($target.LangKey)"
$targets = @()
$topVar = Join-Path $hkcuRoot 'Variables'
if (Test-Path $topVar) { $targets += $topVar }
$profRoot = Join-Path $hkcuRoot 'Profiles'
if (Test-Path $profRoot) {
Get-ChildItem $profRoot -ErrorAction SilentlyContinue | ForEach-Object {
$pv = Join-Path $_.PSPath 'Variables'
if (Test-Path $pv) { $targets += $pv }
}
}
$removedCount = 0
foreach ($t in $targets) {
$cur = (Get-ItemProperty -Path $t -Name 'TRUSTEDPATHS' -ErrorAction SilentlyContinue).TRUSTEDPATHS
if (-not $cur) { continue }
# 分割后去除每段首尾空白,统一比较
$allParts = $cur.Split(';') | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' }
$keepParts = $allParts | Where-Object { -not $_.Equals($scriptDir, [StringComparison]::OrdinalIgnoreCase) }
$hasOurs = ($allParts | Where-Object { $_.Equals($scriptDir, [StringComparison]::OrdinalIgnoreCase) }).Count -gt 0
$shortName = $t -replace '.*\\Profiles\\','Profile\' -replace '\\Variables',''
if (-not $hasOurs) {
Write-Host " 未包含: $shortName 跳过" -ForegroundColor DarkGray
continue
}
if ($keepParts.Count -eq 0) {
# 全部都是本目录,删除整个值
Remove-ItemProperty -Path $t -Name 'TRUSTEDPATHS' -ErrorAction SilentlyContinue
Write-Host " 已清空: $shortName" -ForegroundColor Green
} else {
$newVal = $keepParts -join ';'
Set-ItemProperty -Path $t -Name 'TRUSTEDPATHS' -Value $newVal -Type String -Force
Write-Host " 已移除: $shortName" -ForegroundColor Green
}
$removedCount++
}
if ($removedCount -eq 0) {
Write-Host " 无需修改(TRUSTEDPATHS 中未包含本目录)" -ForegroundColor DarkGray
}
Write-Host ""
# --- 4. 清理 acaddoc.lsp 中的 CADCJ 加载逻辑 ---
Write-Host "[4/4] 清理 acaddoc.lsp 自动加载脚本..." -ForegroundColor Green
$acadDirName = Split-Path $target.Location -Leaf
$roamingBase = Join-Path $env:APPDATA "Autodesk\$acadDirName\$($target.Version)\chs\Support"
$installSupport = Join-Path $target.Location "Support"
$candidateDirs = @($roamingBase, $installSupport) | Select-Object -Unique
$supDir = $null
foreach ($d in $candidateDirs) {
if (Test-Path $d) { $supDir = $d; break }
}
if (-not $supDir) {
Write-Host " 未找到 Support 目录,跳过" -ForegroundColor DarkGray
} else {
$lspPath = Join-Path $supDir 'acaddoc.lsp'
if (-not (Test-Path $lspPath)) {
Write-Host " acaddoc.lsp 不存在,跳过" -ForegroundColor DarkGray
} else {
# 读取(尝试 GB2312,失败则用默认编码)
$content = $null
try {
$content = [System.IO.File]::ReadAllText($lspPath, [System.Text.Encoding]::GetEncoding('GB2312'))
} catch {
$content = Get-Content $lspPath -Raw -ErrorAction SilentlyContinue
}
if (-not $content) {
Write-Host " acaddoc.lsp 为空或无法读取,跳过" -ForegroundColor DarkGray
} elseif ($content -notmatch 'CADCJ|cadcj') {
Write-Host " acaddoc.lsp 中无 CADCJ 加载逻辑,跳过" -ForegroundColor DarkGray
} else {
# 判断是否为纯 CADCJ 文件(以 ;;; CADCJ 开头或整个文件就是 CADCJ 块)
# 移除 CADCJ 加载块(从 ;;; CADCJ 标记开始到 (princ) 结束)
$pattern = '(?s)\s*;;; CADCJ.*?\(princ\)\s*'
$newContent = [regex]::Replace($content, $pattern, "`r`n")
# 清理多余空行
$newContent = $newContent -replace "(`r`n){3,}", "`r`n`r`n"
$newContent = $newContent.TrimEnd()
try {
if ([string]::IsNullOrWhiteSpace($newContent)) {
# 文件清空了,删除文件
Remove-Item $lspPath -Force
Write-Host " 已删除: $lspPath(文件仅含 CADCJ 内容)" -ForegroundColor Green
} else {
# 保留其他内容,只移除 CADCJ 块
[System.IO.File]::WriteAllText($lspPath, $newContent + "`r`n", [System.Text.Encoding]::GetEncoding('GB2312'))
Write-Host " 已清理 CADCJ 加载逻辑,保留其他内容: $lspPath" -ForegroundColor Green
}
} catch {
# 写入失败时提权
Write-Host " 写入失败,尝试提权: $($_.Exception.Message)" -ForegroundColor Yellow
$tmpLsp = Join-Path $env:TEMP 'cadcj_acaddoc_clean.lsp'
if ([string]::IsNullOrWhiteSpace($newContent)) {
$delCmd = "Remove-Item '$lspPath' -Force -ErrorAction SilentlyContinue"
$p = Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile","-Command",$delCmd -Verb RunAs -Wait -PassThru
if ($p.ExitCode -eq 0) {
Write-Host " 已删除(提权): $lspPath" -ForegroundColor Green
}
} else {
[System.IO.File]::WriteAllText($tmpLsp, $newContent + "`r`n", [System.Text.Encoding]::GetEncoding('GB2312'))
$copyCmd = "Copy-Item '$tmpLsp' '$lspPath' -Force"
$p = Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile","-Command",$copyCmd -Verb RunAs -Wait -PassThru
if ($p.ExitCode -eq 0) {
Write-Host " 已清理(提权): $lspPath" -ForegroundColor Green
}
}
Remove-Item $tmpLsp -Force -ErrorAction SilentlyContinue
}
}
}
}
Write-Host ""
# --- 完成 ---
Write-Host "======================================================" -ForegroundColor Cyan
Write-Host " 卸载完成!" -ForegroundColor Green
Write-Host "======================================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "卸载摘要:" -ForegroundColor White
Write-Host " AutoCAD: $($target.Product) ($($target.Version))" -ForegroundColor White
Write-Host " HKLM 注册: 已删除 CADCJ 节点" -ForegroundColor White
Write-Host " TRUSTEDPATHS: 已移除 $scriptDir" -ForegroundColor White
Write-Host " acaddoc.lsp: 已清理 CADCJ 加载逻辑" -ForegroundColor White
Write-Host ""
Write-Host "插件文件本身未删除(cadcj.dll 等),如需彻底删除请手动移除目录:" -ForegroundColor Yellow
Write-Host " $scriptDir" -ForegroundColor Yellow
Write-Host ""
if (-not $env:CADCJ_SILENT) { Read-Host "按回车退出" }
-26
View File
@@ -1,26 +0,0 @@
@echo off
chcp 936 >nul
title 成套报价 CAD 插件安装程序
REM 切换到批处理文件所在目录(支持从任意位置运行)
cd /d "%~dp0"
REM 检查 PowerShell 脚本是否存在
if not exist "安装CAD插件.ps1" (
echo [错误] 未找到 安装CAD插件.ps1
echo 请确保本批处理文件与 安装CAD插件.ps1 在同一目录。
pause
exit /b 1
)
REM 以管理员身份运行 PowerShell 脚本(避免 HKLM 写入提权弹窗中断)
powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process powershell -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','%~dp0安装CAD插件.ps1' -Verb RunAs -Wait"
REM 若用户取消提权,则非提权运行(HKLM 写入会自动提权,acaddoc.lsp 和 TRUSTEDPATHS 无需管理员)
if errorlevel 1 (
echo.
echo [提示] 管理员提权被取消,尝试非提权运行...
powershell -NoProfile -ExecutionPolicy Bypass -File "安装CAD插件.ps1"
)
pause
-309
View File
@@ -1,309 +0,0 @@
# ===========================================================================
# 成套报价 CAD 插件 - 通用安装脚本
# 适用于任何电脑、任何已安装的 AutoCAD 版本(2010+)
# 用法:以管理员身份运行,或在 PowerShell 中执行本脚本
# ===========================================================================
# --- 0. 环境与自检 ---
$ErrorActionPreference = 'Stop'
# $PSScriptRoot 在 -File 模式下可靠返回脚本所在目录(PS 3.0+)
$scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }
$scriptDir = $scriptDir.TrimEnd('\') # 统一去除尾部反斜杠,便于比较
$dllPath = Join-Path $scriptDir 'cadcj.dll'
if (-not (Test-Path $dllPath)) {
Write-Host "[错误] 未找到 cadcj.dll,请确保脚本与 cadcj.dll 在同一目录。" -ForegroundColor Red
Write-Host " 当前目录: $scriptDir" -ForegroundColor Yellow
if (-not $env:CADCJ_SILENT) { Read-Host "按回车退出" }
exit 1
}
# 检测是否管理员(写 HKLM 需要)
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "[提示] 当前未以管理员身份运行,HKLM 注册表写入将自动提权。" -ForegroundColor Yellow
Write-Host " acaddoc.lsp 和 TRUSTEDPATHS 无需管理员权限。" -ForegroundColor Yellow
Write-Host ""
}
Write-Host "======================================================" -ForegroundColor Cyan
Write-Host " 成套报价 CAD 插件安装程序" -ForegroundColor Cyan
Write-Host " 插件目录: $scriptDir" -ForegroundColor Cyan
Write-Host "======================================================" -ForegroundColor Cyan
Write-Host ""
# --- 1. 检测已安装的 AutoCAD 版本 ---
Write-Host "[1/4] 检测 AutoCAD 安装..." -ForegroundColor Green
# 同时检测 64 位和 32 位注册表视图
$acadInstalls = @()
$regRoots = @(
'HKLM:\SOFTWARE\Autodesk\AutoCAD',
'HKLM:\SOFTWARE\WOW6432Node\Autodesk\AutoCAD'
)
foreach ($root in $regRoots) {
if (-not (Test-Path $root)) { continue }
# 遍历每个 Rxx.0 版本(如 R22.0=2018, R23.0=2020, R24.0=2022...)
Get-ChildItem $root -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^R\d+\.0$' } | ForEach-Object {
$verKey = $_.PSPath
$verNum = $_.PSChildName # 如 R22.0
# 遍历该版本下的语言变体(如 ACAD-1001:804)
Get-ChildItem $verKey -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^ACAD-\d+:\d+$' } | ForEach-Object {
$langKey = $_.PSPath
$props = Get-ItemProperty -Path $langKey -ErrorAction SilentlyContinue
$loc = $props.AcadLocation
$prod = $props.ProductName
if ($loc -and (Test-Path $loc)) {
$acadInstalls += [PSCustomObject]@{
Version = $verNum
LangKey = $_.PSChildName
Location = $loc
Product = $prod
RegRoot = $root
HKLMKey = $langKey
}
}
}
}
}
if ($acadInstalls.Count -eq 0) {
Write-Host "[错误] 未检测到已安装的 AutoCAD。" -ForegroundColor Red
if (-not $env:CADCJ_SILENT) { Read-Host "按回车退出" }
exit 1
}
Write-Host "找到 $($acadInstalls.Count) 个 AutoCAD 安装:" -ForegroundColor Green
for ($i = 0; $i -lt $acadInstalls.Count; $i++) {
$a = $acadInstalls[$i]
Write-Host (" [{0}] {1} ({2}) - {3}" -f $i, $a.Product, $a.Version, $a.Location) -ForegroundColor White
}
Write-Host ""
# 若有多个,让用户选择
$target = $acadInstalls[0]
if ($acadInstalls.Count -gt 1) {
if ($env:CADCJ_SILENT) {
# 静默模式:默认选第一个,不交互
Write-Host "[静默模式] 检测到多个 AutoCAD,默认选择第一个: $($target.Product)" -ForegroundColor Yellow
} else {
do {
$sel = Read-Host "请选择要安装的 AutoCAD 序号 (0-$($acadInstalls.Count - 1)),默认 0"
if ([string]::IsNullOrWhiteSpace($sel)) { $sel = '0' }
} until ($sel -match '^\d+$' -and [int]$sel -lt $acadInstalls.Count)
$target = $acadInstalls[[int]$sel]
}
}
Write-Host ""
Write-Host ("目标: {0} ({1})" -f $target.Product, $target.Version) -ForegroundColor Cyan
Write-Host ("路径: {0}" -f $target.Location) -ForegroundColor Cyan
Write-Host ""
# --- 2. 修正 MODULE 路径到 HKLM ---
Write-Host "[2/4] 注册 AutoCAD 自动加载(HKLM)..." -ForegroundColor Green
# HKLM 路径(去除 HKLM: 前缀,得到 SOFTWARE\Autodesk\AutoCAD\Rxx.0\ACAD-xxxx:xxx\Apps\CADCJ)
$hklmPath = $target.HKLMKey -replace '^HKLM:\\', ''
$appsPath = "HKLM:\$hklmPath\Apps\CADCJ"
# 写入函数(管理员直接写,非管理员生成临时 ps1 提权执行)
function Write-HklmReg {
param($Path, $Dll)
if (-not (Test-Path $Path)) { New-Item -Path $Path -Force | Out-Null }
Set-ItemProperty -Path $Path -Name 'DESCRIPTION' -Value '成套报价插件' -Type String -Force
Set-ItemProperty -Path $Path -Name 'LOADCTRLS' -Value 2 -Type DWord -Force
Set-ItemProperty -Path $Path -Name 'MANAGED' -Value 1 -Type DWord -Force
Set-ItemProperty -Path $Path -Name 'MODULE' -Value $Dll -Type String -Force
}
if ($isAdmin) {
Write-HklmReg -Path $appsPath -Dll $dllPath
Write-Host " HKLM 注册完成" -ForegroundColor Green
} else {
# 生成临时 ps1 提权执行(避免字符串嵌套转义问题)
$tmpPs1 = Join-Path $env:TEMP "cadcj_install_hklm.ps1"
$tmpContent = @"
`$ErrorActionPreference = 'Stop'
`$path = '$appsPath'
`$dll = '$dllPath'
if (-not (Test-Path `$path)) { New-Item -Path `$path -Force | Out-Null }
Set-ItemProperty -Path `$path -Name 'DESCRIPTION' -Value '成套报价插件' -Type String -Force
Set-ItemProperty -Path `$path -Name 'LOADCTRLS' -Value 2 -Type DWord -Force
Set-ItemProperty -Path `$path -Name 'MANAGED' -Value 1 -Type DWord -Force
Set-ItemProperty -Path `$path -Name 'MODULE' -Value `$dll -Type String -Force
Write-Host ' HKLM 注册完成'
"@
$tmpContent | Out-File -FilePath $tmpPs1 -Encoding UTF8 -Force
$p = Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile","-ExecutionPolicy","Bypass","-File",$tmpPs1 -Verb RunAs -Wait -PassThru
if ($p.ExitCode -ne 0) {
Write-Host "[警告] HKLM 写入失败(用户取消提权?)。不影响后续安装,acaddoc.lsp 会自动加载。" -ForegroundColor Yellow
} else {
Write-Host " HKLM 注册完成" -ForegroundColor Green
}
Remove-Item $tmpPs1 -Force -ErrorAction SilentlyContinue
}
Write-Host ""
# --- 3. 添加 TRUSTEDPATHS 到所有用户配置(HKCU) ---
Write-Host "[3/4] 添加受信任路径(TRUSTEDPATHS)..." -ForegroundColor Green
# 确定 HKCU 根路径
$hkcuRoot = "HKCU:\SOFTWARE\Autodesk\AutoCAD\$($target.Version)\$($target.LangKey)"
$targets = @()
# 顶层 Variables
$topVar = Join-Path $hkcuRoot 'Variables'
if (Test-Path $topVar) { $targets += $topVar }
# 各 Profile 下的 Variables
$profRoot = Join-Path $hkcuRoot 'Profiles'
if (Test-Path $profRoot) {
Get-ChildItem $profRoot -ErrorAction SilentlyContinue | ForEach-Object {
$pv = Join-Path $_.PSPath 'Variables'
if (Test-Path $pv) { $targets += $pv }
}
}
$addedCount = 0
foreach ($t in $targets) {
$cur = (Get-ItemProperty -Path $t -Name 'TRUSTEDPATHS' -ErrorAction SilentlyContinue).TRUSTEDPATHS
if ($cur -and ($cur.Split(';') -contains $scriptDir)) {
Write-Host " 已存在: $($t -replace '.*\\Profiles\\','Profile\') 跳过" -ForegroundColor DarkGray
continue
}
if ($cur) {
$newVal = "$cur;$scriptDir"
} else {
$newVal = $scriptDir
}
try {
New-ItemProperty -Path $t -Name 'TRUSTEDPATHS' -Value $newVal -PropertyType String -Force | Out-Null
$shortName = $t -replace '.*\\Profiles\\','Profile\' -replace '\\Variables',''
Write-Host " 已添加: $shortName" -ForegroundColor Green
$addedCount++
} catch {
Write-Host " 失败: $t - $($_.Exception.Message)" -ForegroundColor Red
}
}
if ($addedCount -eq 0 -and $targets.Count -gt 0) {
Write-Host " 所有配置已包含本目录,无需修改" -ForegroundColor DarkGray
}
Write-Host ""
# --- 4. 创建 acaddoc.lsp 自动加载(核心机制) ---
Write-Host "[4/4] 创建 acaddoc.lsp 自动加载脚本..." -ForegroundColor Green
# 确定 Support 目录(优先用户漫游目录,其次 AutoCAD 安装目录)
# 漫游目录路径模式:%APPDATA%\Autodesk\AutoCAD 20XX\Rxx.0\chs\Support
$acadDirName = Split-Path $target.Location -Leaf # 如 "AutoCAD 2018"
$roamingBase = Join-Path $env:APPDATA "Autodesk\$acadDirName\$($target.Version)\chs\Support"
$installSupport = Join-Path $target.Location "Support"
$candidateDirs = @($roamingBase, $installSupport) | Select-Object -Unique
$supDir = $null
foreach ($d in $candidateDirs) {
if (Test-Path $d) { $supDir = $d; break }
}
if (-not $supDir) {
# 创建漫游目录
$supDir = $roamingBase
New-Item -ItemType Directory -Path $supDir -Force | Out-Null
Write-Host " 创建目录: $supDir" -ForegroundColor Yellow
}
$lspPath = Join-Path $supDir 'acaddoc.lsp'
# LISP 代码(路径用双反斜杠转义)
$dllPathEscaped = $dllPath -replace '\\','\\\\'
$lispCode = @"
;;; CADCJ 自动加载 - 由安装脚本生成
;;; 每会话首次打开文档时通过 NETLOAD 加载成套报价插件
;;; 使用内存全局变量,进程退出后自动清除,避免持久化导致跳过加载
(vl-load-com)
(if (not *cadcj-loaded*)
(progn
(setq *cadcj-loaded* t)
(setq #cadcj-fd (getvar "FILEDIA"))
(setvar "FILEDIA" 0)
(vl-catch-all-apply
'(lambda ()
(command "NETLOAD" "$dllPathEscaped")
)
)
(setvar "FILEDIA" #cadcj-fd)
(vl-propagate '*cadcj-loaded*)
)
)
(princ)
"@
# 检查是否已有 acaddoc.lsp(避免覆盖用户现有内容)
$needMerge = $false
if (Test-Path $lspPath) {
$existing = Get-Content $lspPath -Raw -ErrorAction SilentlyContinue
if ($existing -and ($existing -match 'CADCJ|cadcj')) {
Write-Host " acaddoc.lsp 已包含 CADCJ 加载逻辑,跳过" -ForegroundColor DarkGray
} elseif ($existing) {
$needMerge = $true
Write-Host " 检测到现有 acaddoc.lsp,将追加 CADCJ 加载逻辑" -ForegroundColor Yellow
}
}
try {
if ($needMerge) {
# 追加到现有文件末尾
$existing + "`r`n" + $lispCode | Out-File -FilePath $lspPath -Encoding Default -Append -Force
} else {
# GB2312 编码写入(AutoCAD 正确读取中文路径)
[System.IO.File]::WriteAllText($lspPath, $lispCode, [System.Text.Encoding]::GetEncoding('GB2312'))
}
Write-Host " 已创建: $lspPath" -ForegroundColor Green
} catch {
# AppData 写入失败时提权
Write-Host " 写入失败,尝试提权: $($_.Exception.Message)" -ForegroundColor Yellow
$tmpLsp = Join-Path $env:TEMP 'cadcj_acaddoc.lsp'
[System.IO.File]::WriteAllText($tmpLsp, $lispCode, [System.Text.Encoding]::GetEncoding('GB2312'))
$copyCmd = "Copy-Item '$tmpLsp' '$lspPath' -Force"
$p = Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile","-Command",$copyCmd -Verb RunAs -Wait -PassThru
if ($p.ExitCode -eq 0) {
Write-Host " 已创建(提权): $lspPath" -ForegroundColor Green
} else {
Write-Host " [错误] 无法创建 acaddoc.lsp" -ForegroundColor Red
}
Remove-Item $tmpLsp -Force -ErrorAction SilentlyContinue
}
Write-Host ""
# --- 5. 同步更新 .reg 文件(便于记录) ---
$regFile = Join-Path $scriptDir '注册CAD自动加载.reg'
$regKeyHklm = $appsPath -replace '^HKLM:\\','HKEY_LOCAL_MACHINE\'
$regContent = @"
Windows Registry Editor Version 5.00
[$regKeyHklm]
"DESCRIPTION"="成套报价插件"
"LOADCTRLS"=dword:00000002
"MANAGED"=dword:00000001
"MODULE"="$($dllPath -replace '\\','\\')"
"@
try {
$regContent | Out-File -FilePath $regFile -Encoding Default -Force
Write-Host " 已更新: $regFile" -ForegroundColor DarkGray
} catch {}
Write-Host ""
# --- 完成 ---
Write-Host "======================================================" -ForegroundColor Cyan
Write-Host " 安装完成!" -ForegroundColor Green
Write-Host "======================================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "安装摘要:" -ForegroundColor White
Write-Host " AutoCAD: $($target.Product) ($($target.Version))" -ForegroundColor White
Write-Host " 插件DLL: $dllPath" -ForegroundColor White
Write-Host " LSP文件: $lspPath" -ForegroundColor White
Write-Host " 加载方式: acaddoc.lsp (NETLOAD)" -ForegroundColor White
Write-Host ""
Write-Host "现在启动 AutoCAD 并打开任意图纸,插件会自动加载。" -ForegroundColor Yellow
Write-Host ""
if (-not $env:CADCJ_SILENT) { Read-Host "按回车退出" }
-71
View File
@@ -1,71 +0,0 @@
@echo off
chcp 65001 >nul
REM ============================================
REM 成套报价 CAD 插件 - 就地安装脚本
REM 功能:把【本脚本所在目录】的 cadcj.dll 注册为 CAD 自动加载
REM 原则:在哪个目录运行,就安装哪个目录(测试目录/安装目录通用)
REM 用法:双击运行(无需管理员权限,写的是用户级注册表 HKCU)
REM 更新 DLL 后:先关 CAD → 替换本目录 cadcj.dll → 再运行本脚本不需要,
REM 注册表已指向本目录,直接重启 CAD 即加载新版
REM ============================================
setlocal enabledelayedexpansion
REM 取脚本所在目录(去掉尾部反斜杠)
set "INSTDIR=%~dp0"
if "%INSTDIR:~-1%"=="\" set "INSTDIR=%INSTDIR:~0,-1%"
set "DLLPATH=%INSTDIR%\cadcj.dll"
REM 检查本目录是否有 cadcj.dll
if not exist "%DLLPATH%" (
echo [错误] 本目录没有 cadcj.dll,无法安装。
echo 当前目录: %INSTDIR%
pause
exit /b 1
)
echo ==============================================
echo 成套报价 CAD 插件 - 就地安装
echo 插件目录: %INSTDIR%
echo ==============================================
echo.
REM 检查 CAD 是否在运行(在运行也能写注册表,但新DLL要重启CAD才生效)
tasklist /FI "IMAGENAME eq acad.exe" 2>nul | find /I "acad.exe" >nul
if %ERRORLEVEL% EQU 0 (
echo [提示] AutoCAD 正在运行:注册完成后请重启 CAD 才能生效。
echo.
)
REM 枚举所有已安装的 AutoCAD 版本(HKCU 用户级,无需管理员)
REM ★ findstr "^HKEY_" 只取子键行,过滤掉 CurVer 这类值行
set FOUND=0
for /f "delims=" %%K in ('reg query "HKCU\SOFTWARE\Autodesk\AutoCAD" 2^>nul ^| findstr /I /C:"HKEY_"') do (
for /f "delims=" %%P in ('reg query "%%K" 2^>nul ^| findstr /I /C:"HKEY_" ^| findstr /I "ACAD-"') do (
set "APPSKEY=%%P\Apps\CADCJ"
reg add "!APPSKEY!" /v LOADCTRLS /t REG_DWORD /d 2 /f >nul
reg add "!APPSKEY!" /v MANAGED /t REG_DWORD /d 1 /f >nul
reg add "!APPSKEY!" /v MODULE /t REG_SZ /d "%DLLPATH%" /f >nul
reg add "!APPSKEY!" /v DESCRIPTION /t REG_SZ /d "ChengTao BaoJia Plugin" /f >nul
echo [OK] 已注册: !APPSKEY!
echo MODULE = %DLLPATH%
set FOUND=1
)
)
if %FOUND% EQU 0 (
echo [错误] 未检测到已安装的 AutoCAD(R22.0=2018 等)。
echo 请确认 AutoCAD 已安装后重试。
pause
exit /b 1
)
echo.
echo ==============================================
echo 安装完成!
echo CAD 自动加载: %DLLPATH%
echo 用户库CSV : 本目录下最新的 用户库_*.csv
echo 数据库sjk : 本目录 sjk\ 下
echo 重启 AutoCAD 即生效。
echo ==============================================
pause
File diff suppressed because it is too large Load Diff
-132
View File
@@ -1,132 +0,0 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace MyApp
{
/// <summary>
/// 新建项目 窗口(简化版,不依赖企业信息)。
/// UI 布局见 新建项目.ui.cs,本文件只含交互逻辑。
/// </summary>
public partial class 新建项目 : Form
{
// 价格格式化选项(与主项目 价格格式化.cs 保持一致)
private static readonly string[] 小数位选项 =
{
"保留整数", "保留1位小数", "保留2位小数", "保留3位小数",
"保留4位小数", "保留5位小数", "保留6位小数"
};
private static readonly string[] 取整方式选项 =
{
"不取整", "四舍五入", "四舍五入到角", "四舍五入到元",
"四舍五入到十元", "向上取整到元", "最近5元", "最近10元"
};
private readonly string _dbPath;
private readonly string _tableName;
public 新建项目() : this(null, null) { }
/// <summary>带数据库路径的构造函数(用于自动生成项目编号)。</summary>
public 新建项目(string dbPath, string tableName)
{
InitializeComponent();
_dbPath = dbPath;
_tableName = tableName;
InitPriceFormatCombos();
this.Load += 新建项目_Load;
}
private void InitPriceFormatCombos()
{
cmb单台价格.Items.Clear();
cmb单台价格.Items.AddRange(小数位选项);
cmb项目总价.Items.Clear();
cmb项目总价.Items.AddRange(小数位选项);
comboBox1.Items.Clear();
comboBox1.Items.AddRange(取整方式选项);
comboBox2.Items.Clear();
comboBox2.Items.AddRange(取整方式选项);
}
private void 新建项目_Load(object sender, EventArgs e)
{
FillAutoFields();
}
/// <summary>自动填充项目日期(当天)和项目编号(yyyyMMdd+3位序号)。</summary>
private void FillAutoFields()
{
DateTime today = DateTime.Today;
txt项目日期.Text = today.ToString("yyyy-MM-dd");
string datePart = today.ToString("yyyyMMdd");
int seq = GetNextSeqForDate(datePart);
txt项目编号.Text = datePart + seq.ToString("000");
txt项目编号.ReadOnly = true;
txt项目编号.TabStop = false;
txt项目编号.BackColor = System.Drawing.SystemColors.Control;
}
/// <summary>查数据库当天最大序号+1,失败返回1。</summary>
private int GetNextSeqForDate(string datePart)
{
if (string.IsNullOrEmpty(datePart) ||
string.IsNullOrEmpty(_dbPath) ||
string.IsNullOrEmpty(_tableName) ||
!System.IO.File.Exists(_dbPath))
{
return 1;
}
try
{
string connStr = "Data Source=" + _dbPath + ";Version=3;";
using (var conn = new System.Data.SQLite.SQLiteConnection(connStr))
{
conn.Open();
string sql =
"SELECT MAX(CAST(SUBSTR(项目编号, 9) AS INTEGER)) " +
"FROM " + _tableName + " " +
"WHERE SUBSTR(项目编号, 1, 8) = '" + datePart + "';";
using (var cmd = new System.Data.SQLite.SQLiteCommand(sql, conn))
{
object result = cmd.ExecuteScalar();
if (result == null || result == DBNull.Value) return 1;
int maxSeq;
if (int.TryParse(result.ToString(), out maxSeq)) return maxSeq + 1;
return 1;
}
}
}
catch { return 1; }
}
/// <summary>收集对话框字段,以列名为键返回(供 Form3 写入数据库)。</summary>
public Dictionary<string, string> GetInputValues()
{
var values = new Dictionary<string, string>();
AddIfNotEmpty(values, "项目编号", txt项目编号.Text);
AddIfNotEmpty(values, "项目日期", txt项目日期.Text);
AddIfNotEmpty(values, "项目名称", txt项目名称.Text);
AddIfNotEmpty(values, "客户名称", txt客户名称.Text);
AddIfNotEmpty(values, "客户地址", txt客户地址.Text);
AddIfNotEmpty(values, "联系人", txt联系人.Text);
AddIfNotEmpty(values, "联系电话", txt联系电话.Text);
AddIfNotEmpty(values, "备注", txt备注.Text);
AddIfNotEmpty(values, "成套厂名称", txt成套厂名称.Text);
AddIfNotEmpty(values, "成套厂地址", txt成套厂地址.Text);
AddIfNotEmpty(values, "成套厂联系人", txt成套厂联系人.Text);
AddIfNotEmpty(values, "成套厂联系电话", txt成套厂联系电话.Text);
values["单台小数位"] = (cmb单台价格.SelectedItem ?? cmb单台价格.Text ?? "").ToString();
values["项目小数位"] = (cmb项目总价.SelectedItem ?? cmb项目总价.Text ?? "").ToString();
values["单台取整方式"] = (comboBox1.SelectedItem ?? comboBox1.Text ?? "").ToString();
values["项目取整方式"] = (comboBox2.SelectedItem ?? comboBox2.Text ?? "").ToString();
return values;
}
private static void AddIfNotEmpty(Dictionary<string, string> dict, string key, string value)
{
if (!string.IsNullOrWhiteSpace(value)) dict[key] = value.Trim();
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,7 +0,0 @@
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\R22.0\ACAD-1001:804\Apps\CADCJ]
"DESCRIPTION"="成套报价插件"
"LOADCTRLS"=dword:00000002
"MANAGED"=dword:00000001
"MODULE"="C:\\Users\\099978\\Documents\\SharpDevelop Projects\\成套报价软件\\成套报价软件\\cadcj\\cadcj.dll"
File diff suppressed because it is too large Load Diff