Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ x86/
[Oo]bj/
Binaries/
Standalone/
publish/

# Visual Studio
.vs/
Expand Down Expand Up @@ -43,3 +44,6 @@ Thumbs.db
ehthumbs.db
Desktop.ini

# VS project upgrade/migration reports (auto-generated)
UpgradeLog*.htm

2 changes: 1 addition & 1 deletion DrawingListUC/AcadComUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

namespace DrawingListUC
{
internal static class AcadComUtils
public static class AcadComUtils
{
// -------------------- PUBLIC API --------------------

Expand Down
191 changes: 191 additions & 0 deletions DwgExportManager/AcadSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using DrawingListUC;

namespace DwgExportManager
{
// Dieu khien AutoCAD qua COM (attach vao instance dang chay hoac tao moi),
// mo/kich hoat ban ve va chuyen tab Model/Layout.
// Tai su dung AcadComUtils - nghiep vu ket noi AutoCAD da co san trong ScriptPro (DrawingListUC).
public class AcadSession
{
// HRESULT AutoCAD/COM tra ve khi ung dung dang ban (dang hien dialog, dang ve lai man hinh...)
// ScriptUI/DrawingListUC khong gap loi nay vi no chay tren luong UI (STA) co dang ky
// IOleMessageFilter (xem MessageFilter.cs) de COM tu dong retry. DwgExportManager goi COM
// ca tu luong nen (BackgroundWorker, MTA) - IOleMessageFilter KHONG co tac dung voi MTA,
// nen phai tu bat loi va retry thu cong o day.
private const int RPC_E_CALL_REJECTED = unchecked((int)0x80010001);
private const int RPC_E_SERVERCALL_RETRYLATER = unchecked((int)0x8001010A);
private const int MaxRetries = 60; // toi da ~15s (60 x 250ms)
private const int RetryDelayMs = 250;

private object _acadApp;

// Goi InvokeMember co tu dong retry khi AutoCAD bao "busy"
private static object Invoke(object target, string name, BindingFlags flags, object[] args)
{
int attempt = 0;
while (true)
{
try
{
return target.GetType().InvokeMember(name, flags, null, target, args);
}
catch (COMException ex) when (
(ex.HResult == RPC_E_CALL_REJECTED || ex.HResult == RPC_E_SERVERCALL_RETRYLATER) &&
attempt < MaxRetries)
{
attempt++;
Thread.Sleep(RetryDelayMs);
}
}
}

public object EnsureAcadRunning()
{
if (_acadApp != null)
{
try
{
// Kiem tra COM object con song khong (AutoCAD co the da bi dong tay)
Invoke(_acadApp, "Visible", BindingFlags.GetProperty, null);
return _acadApp;
}
catch
{
_acadApp = null;
}
}

_acadApp = AcadComUtils.TryGetAnyRunningAcad();
if (_acadApp == null)
_acadApp = AcadComUtils.CreateLatestAutoCADInstance();

AcadComUtils.SetVisible(_acadApp, true);
return _acadApp;
}

// Mo file (hoac kich hoat lai neu da mo san) va tra ve AcadDocument (COM object)
public object OpenDocument(string dwgPath)
{
object acadApp = EnsureAcadRunning();

object documents = Invoke(acadApp, "Documents", BindingFlags.GetProperty, null);

int count = (int)Invoke(documents, "Count", BindingFlags.GetProperty, null);

for (int i = 0; i < count; i++)
{
object existing = Invoke(documents, "Item", BindingFlags.InvokeMethod, new object[] { i });

string fullName = (string)Invoke(existing, "FullName", BindingFlags.GetProperty, null);

if (string.Equals(fullName, dwgPath, StringComparison.OrdinalIgnoreCase))
{
ActivateDocument(existing);
return existing;
}
}

object opened = Invoke(documents, "Open", BindingFlags.InvokeMethod,
new object[] { dwgPath, false, " " });

// Cho AutoCAD ve xong ban ve vua mo truoc khi goi tiep lenh COM khac,
// giam kha nang gap "application is busy" ngay sau khi Open.
Thread.Sleep(800);

ActivateDocument(opened);
return opened;
}

public void ActivateDocument(object document)
{
try
{
Invoke(document, "Activate", BindingFlags.InvokeMethod, null);
}
catch { }

try
{
AcadComUtils.SetVisible(_acadApp, true);
}
catch { }
}

// Chuyen sang tab Model hoac Layout co ten tuong ung
public void SetActiveTab(object document, string tabName)
{
if (string.IsNullOrEmpty(tabName) ||
string.Equals(tabName, "Model", StringComparison.OrdinalIgnoreCase))
return;

try
{
object layouts = Invoke(document, "Layouts", BindingFlags.GetProperty, null);

object layout = Invoke(layouts, "Item", BindingFlags.InvokeMethod, new object[] { tabName });

Invoke(document, "ActiveLayout", BindingFlags.SetProperty, new object[] { layout });

// Cho AutoCAD chuyen tab xong truoc khi goi tiep lenh COM khac
Thread.Sleep(300);
}
catch
{
// Khong tim thay layout (co the da bi doi ten) - giu nguyen tab hien tai
}
}

public void SetVariable(object document, string varName, object value)
{
try
{
Invoke(document, "SetVariable", BindingFlags.InvokeMethod, new object[] { varName, value });
}
catch { }
}

public int GetIntVariable(object document, string varName, int defaultValue)
{
try
{
object result = Invoke(document, "GetVariable", BindingFlags.InvokeMethod, new object[] { varName });
return Convert.ToInt32(result);
}
catch
{
return defaultValue;
}
}

public string GetStringVariable(object document, string varName, string defaultValue)
{
try
{
object result = Invoke(document, "GetVariable", BindingFlags.InvokeMethod, new object[] { varName });
return result?.ToString() ?? defaultValue;
}
catch
{
return defaultValue;
}
}

public void SendCommand(object document, string commandText)
{
Invoke(document, "SendCommand", BindingFlags.InvokeMethod, new object[] { commandText });
}

public void CloseDocument(object document)
{
try
{
Invoke(document, "Close", BindingFlags.InvokeMethod, new object[] { false, "" });
}
catch { }
}
}
}
7 changes: 7 additions & 0 deletions DwgExportManager/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Application x:Class="DwgExportManager.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
8 changes: 8 additions & 0 deletions DwgExportManager/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Windows;

namespace DwgExportManager
{
public partial class App : Application
{
}
}
68 changes: 68 additions & 0 deletions DwgExportManager/DwgExportManager.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<OutputType>WinExe</OutputType>
<RootNamespace>DwgExportManager</RootNamespace>
<AssemblyName>DwgExportManager</AssemblyName>
<LangVersion>latest</LangVersion>
<Nullable>disable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
<Platforms>AnyCPU;x64</Platforms>
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
<ForceDesignerDpiUnaware>true</ForceDesignerDpiUnaware>
</PropertyGroup>

<PropertyGroup>
<!-- Assembly Information -->
<AssemblyTitle>DwgExportManager</AssemblyTitle>
<Company></Company>
<Product>DwgExportManager</Product>
<Copyright>Copyright 漏 2026</Copyright>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
<OutputPath>bin\Debug\</OutputPath>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE</DefineConstants>
<OutputPath>$(SolutionDir)Binaries\</OutputPath>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
<OutputPath>$(SolutionDir)Binaries\x64\Debug\</OutputPath>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DefineConstants>TRACE</DefineConstants>
<OutputPath>$(SolutionDir)Binaries\x64\Release\</OutputPath>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>

<ItemGroup>
<!-- Tai su dung AcadComUtils (nghiep vu ket noi AutoCAD qua COM) da co san trong ScriptPro -->
<ProjectReference Include="..\DrawingListUC\DrawingListUC.csproj" />
</ItemGroup>

<ItemGroup>
<!-- Doc nhanh danh sach Layout tu file DWG/DXF ma khong can mo AutoCAD -->
<PackageReference Include="ACadSharp" Version="3.7.1" />
</ItemGroup>

</Project>
Loading