388 lines
18 KiB
C#
388 lines
18 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices; // COM 객체 해제를 위해 필요
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Teigha.DatabaseServices;
|
|
using Teigha.Geometry;
|
|
using Teigha.Runtime;
|
|
using Excel = Microsoft.Office.Interop.Excel;
|
|
|
|
namespace DwgExtractorManual.Models
|
|
{
|
|
/// <summary>
|
|
/// DWG 파일에서 Excel로 데이터 내보내기 클래스
|
|
/// AttributeReference, AttributeDefinition, DBText, MText 추출 지원
|
|
/// </summary>
|
|
internal class ExportExcel : IDisposable
|
|
{
|
|
// ODA 서비스 객체
|
|
private Services appServices;
|
|
|
|
// Excel COM 객체들
|
|
private Excel.Application excelApplication;
|
|
private Excel.Workbook workbook1;
|
|
private Excel.Worksheet titleBlockSheet; // Title Block용 시트
|
|
private Excel.Worksheet textEntitiesSheet; // Text Entities용 시트
|
|
|
|
// 각 시트의 현재 행 번호
|
|
private int titleBlockCurrentRow = 2; // 헤더가 1행이므로 데이터는 2행부터 시작
|
|
private int textEntitiesCurrentRow = 2; // 헤더가 1행이므로 데이터는 2행부터 시작
|
|
|
|
// 생성자: ODA 및 Excel 초기화
|
|
public ExportExcel()
|
|
{
|
|
ActivateAndInitializeODA();
|
|
InitializeExcel();
|
|
}
|
|
|
|
// ODA 제품 활성화 및 초기화
|
|
private void ActivateAndInitializeODA()
|
|
{
|
|
var userInfo = "c2FtYW4gZW5naW5lZXJpbmc=";
|
|
var userSignature = "F0kuQTmtVpHtvl/TgaFVGE92/YqGmYR9SLoXckEjnOk8NoAQh7Sg6GQruVC04JqD4C/IipxJYqpqvMfMc2auRMG+cAJCKqKUE2djIMdkUdb+C5IVx2c97fcK5ba3n8DDvB54Upokajl+6j12yD8h8MKGOR3Z3zysObeXD62bFpQgp00GCYTqlxEZtTIRjHIPAfJfix8Y0jtXWWYyVJ3LYOu86as5xtx+hY1aakpYIJiQk/6pGd84qSn/9K1w8nxR7UrFzieDeQ/xM58BHSD4u/ZxVJwvv6Uy10tsdBFBTvfJMAFp05Y7yeyeCNr100tA3iOfmWoXAVRHfxnkPfiYR54aK04QI+R6OGkI+yd1oR5BtmN6BdDt3z8KYK5EpFGJGiJIGoUy5PvkYdJ2VV6xe9JWBiIJuI/tDn1Y+uyTQFA9qaDHnOURriXsRGfy8reDPf1eejybSJxWKkpilG6RXhq3xHlCkjZzh1Q45S+xYXNGatcWMm9nkn20M8Ke5JEVaI9w/p2GE36CHRtRQbt8kfPmsbWNXJCFr4svHW2MPbCKWoyn5XEyMWBnuAKi74zvczB13DKjf29SqSIgF5k/hwy2QrgvnaKzY1k8bw8w2/k0vJXcS3GKOB/ZYDle1tf/lkAD1HtnF9zE18TiXhVnqwAVjwg4ui1RPLn/LMs6b5Y=";
|
|
Services.odActivate(userInfo, userSignature);
|
|
appServices = new Services();
|
|
}
|
|
|
|
// Excel 애플리케이션 및 워크시트 초기화
|
|
private void InitializeExcel()
|
|
{
|
|
try
|
|
{
|
|
var excelApp = new Excel.Application();
|
|
excelApplication = excelApp;
|
|
excelApplication.Visible = false; // WPF에서는 숨김 처리
|
|
Excel.Workbook workbook = excelApp.Workbooks.Add();
|
|
workbook1 = workbook;
|
|
|
|
// Title Block Sheet 설정 (기본 Sheet1)
|
|
titleBlockSheet = (Excel.Worksheet)workbook.Sheets[1];
|
|
titleBlockSheet.Name = "Title Block";
|
|
SetupTitleBlockHeaders();
|
|
|
|
// Text Entities Sheet 추가
|
|
textEntitiesSheet = (Excel.Worksheet)workbook.Sheets.Add();
|
|
textEntitiesSheet.Name = "Text Entities";
|
|
SetupTextEntitiesHeaders();
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Console.WriteLine($"Excel 초기화 중 오류 발생: {ex.Message}");
|
|
ReleaseExcelObjects();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
// Title Block 시트 헤더 설정
|
|
private void SetupTitleBlockHeaders()
|
|
{
|
|
titleBlockSheet.Cells[1, 1] = "Type"; // 예: AttributeReference, AttributeDefinition
|
|
titleBlockSheet.Cells[1, 2] = "Name"; // BlockReference 이름 또는 BlockDefinition 이름
|
|
titleBlockSheet.Cells[1, 3] = "Tag"; // Attribute Tag
|
|
titleBlockSheet.Cells[1, 4] = "Prompt"; // Attribute Prompt
|
|
titleBlockSheet.Cells[1, 5] = "Value"; // Attribute 값 (TextString)
|
|
titleBlockSheet.Cells[1, 6] = "Path"; // 원본 DWG 파일 전체 경로
|
|
titleBlockSheet.Cells[1, 7] = "FileName"; // 원본 DWG 파일 이름만
|
|
|
|
// 헤더 행 스타일
|
|
Excel.Range headerRange = titleBlockSheet.Range["A1:G1"];
|
|
headerRange.Font.Bold = true;
|
|
headerRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightBlue);
|
|
}
|
|
|
|
// Text Entities 시트 헤더 설정
|
|
private void SetupTextEntitiesHeaders()
|
|
{
|
|
textEntitiesSheet.Cells[1, 1] = "Type"; // DBText, MText
|
|
textEntitiesSheet.Cells[1, 2] = "Layer"; // Layer 이름
|
|
textEntitiesSheet.Cells[1, 3] = "Text"; // 실제 텍스트 내용
|
|
textEntitiesSheet.Cells[1, 4] = "Path"; // 원본 DWG 파일 전체 경로
|
|
textEntitiesSheet.Cells[1, 5] = "FileName"; // 원본 DWG 파일 이름만
|
|
|
|
// 헤더 행 스타일
|
|
Excel.Range headerRange = textEntitiesSheet.Range["A1:E1"];
|
|
headerRange.Font.Bold = true;
|
|
headerRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightGreen);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 단일 DWG 파일에서 AttributeReference/AttributeDefinition 데이터를 추출하여
|
|
/// 초기화된 Excel 워크시트에 추가합니다.
|
|
/// </summary>
|
|
/// <param name="filePath">처리할 DWG 파일 경로</param>
|
|
/// <param name="progress">진행 상태 보고를 위한 IProgress 객체</param>
|
|
/// <param name="cancellationToken">작업 취소를 위한 CancellationToken</param>
|
|
/// <returns>성공 시 true, 실패 시 false 반환</returns>
|
|
public bool ExportDwgToExcel(string filePath, IProgress<double> progress = null, CancellationToken cancellationToken = default)
|
|
{
|
|
if (excelApplication == null)
|
|
{
|
|
Console.WriteLine("Excel이 초기화되지 않았습니다.");
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
progress?.Report(0);
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
// ODA Database 객체 생성 및 DWG 파일 읽기
|
|
using (var database = new Database(false, true))
|
|
{
|
|
database.ReadDwgFile(filePath, FileOpenMode.OpenForReadAndWriteNoShare, false, null);
|
|
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
progress?.Report(10);
|
|
|
|
using (var tran = database.TransactionManager.StartTransaction())
|
|
{
|
|
var bt = tran.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable;
|
|
using (var btr = tran.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord)
|
|
{
|
|
int totalEntities = btr.Cast<ObjectId>().Count();
|
|
int processedCount = 0;
|
|
|
|
foreach (ObjectId entId in btr)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
using (var ent = tran.GetObject(entId, OpenMode.ForRead) as Entity)
|
|
{
|
|
// Layer 이름 가져오기 (공통)
|
|
string layerName = GetLayerName(ent.LayerId, tran, database);
|
|
|
|
// AttributeDefinition 추출
|
|
if (ent is AttributeDefinition attDef)
|
|
{
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 1] = attDef.GetType().Name;
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 2] = attDef.BlockName;
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 3] = attDef.Tag;
|
|
|
|
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 4] = attDef.Prompt;
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 5] = attDef.TextString;
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 6] = database.Filename;
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 7] = Path.GetFileName(database.Filename);
|
|
titleBlockCurrentRow++;
|
|
}
|
|
// BlockReference 및 그 안의 AttributeReference 추출
|
|
else if (ent is BlockReference blr)
|
|
{
|
|
foreach (ObjectId attId in blr.AttributeCollection)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
using (var attRef = tran.GetObject(attId, OpenMode.ForRead) as AttributeReference)
|
|
{
|
|
if (attRef != null && attRef.TextString.Trim() !="")
|
|
{
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 1] = attRef.GetType().Name;
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 2] = blr.Name;
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 3] = attRef.Tag;
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 4] = GetPromptFromAttributeReference(tran, blr, attRef.Tag);
|
|
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 5] = attRef.TextString;
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 6] = database.Filename;
|
|
titleBlockSheet.Cells[titleBlockCurrentRow, 7] = Path.GetFileName(database.Filename);
|
|
titleBlockCurrentRow++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// DBText 엔티티 추출 (별도 시트)
|
|
else if (ent is DBText dbText)
|
|
{
|
|
textEntitiesSheet.Cells[textEntitiesCurrentRow, 1] = "DBText"; // Type
|
|
textEntitiesSheet.Cells[textEntitiesCurrentRow, 2] = layerName; // Layer
|
|
textEntitiesSheet.Cells[textEntitiesCurrentRow, 3] = dbText.TextString; // Text
|
|
textEntitiesSheet.Cells[textEntitiesCurrentRow, 4] = database.Filename; // Path
|
|
textEntitiesSheet.Cells[textEntitiesCurrentRow, 5] = Path.GetFileName(database.Filename); // FileName
|
|
textEntitiesCurrentRow++;
|
|
}
|
|
// MText 엔티티 추출 (별도 시트)
|
|
else if (ent is MText mText)
|
|
{
|
|
textEntitiesSheet.Cells[textEntitiesCurrentRow, 1] = "MText"; // Type
|
|
textEntitiesSheet.Cells[textEntitiesCurrentRow, 2] = layerName; // Layer
|
|
textEntitiesSheet.Cells[textEntitiesCurrentRow, 3] = mText.Contents; // Text
|
|
textEntitiesSheet.Cells[textEntitiesCurrentRow, 4] = database.Filename; // Path
|
|
textEntitiesSheet.Cells[textEntitiesCurrentRow, 5] = Path.GetFileName(database.Filename); // FileName
|
|
textEntitiesCurrentRow++;
|
|
}
|
|
}
|
|
|
|
processedCount++;
|
|
double currentProgress = 10.0 + (double)processedCount / totalEntities * 80.0;
|
|
progress?.Report(Math.Min(currentProgress, 90.0));
|
|
}
|
|
}
|
|
|
|
tran.Commit();
|
|
}
|
|
}
|
|
|
|
progress?.Report(100);
|
|
return true;
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
progress?.Report(0);
|
|
return false;
|
|
}
|
|
catch (Teigha.Runtime.Exception ex)
|
|
{
|
|
progress?.Report(0);
|
|
Console.WriteLine($"DWG 파일 처리 중 오류 발생: {ex.Message}");
|
|
return false;
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
progress?.Report(0);
|
|
Console.WriteLine($"일반 오류 발생: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
// Paste the helper function from above here
|
|
public string GetPromptFromAttributeReference(Transaction tr, BlockReference blockref, string tag)
|
|
{
|
|
|
|
string prompt = null;
|
|
|
|
|
|
BlockTableRecord blockDef = tr.GetObject(blockref.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
|
|
if (blockDef == null) return null;
|
|
|
|
foreach (ObjectId objId in blockDef)
|
|
{
|
|
AttributeDefinition attDef = tr.GetObject(objId, OpenMode.ForRead) as AttributeDefinition;
|
|
if (attDef != null)
|
|
{
|
|
if (attDef.Tag.Equals(tag, System.StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
prompt = attDef.Prompt;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return prompt;
|
|
}
|
|
/// <summary>
|
|
/// 현재 Excel 워크북을 지정된 경로에 저장하고 Excel 애플리케이션을 종료합니다.
|
|
/// </summary>
|
|
/// <param name="savePath">Excel 파일을 저장할 전체 경로</param>
|
|
public void SaveAndCloseExcel(string savePath)
|
|
{
|
|
if (workbook1 == null) return;
|
|
|
|
try
|
|
{
|
|
string directory = Path.GetDirectoryName(savePath);
|
|
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
|
{
|
|
Directory.CreateDirectory(directory);
|
|
}
|
|
|
|
workbook1.SaveAs(savePath, AccessMode: Excel.XlSaveAsAccessMode.xlNoChange);
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Console.WriteLine($"Excel 파일 저장 중 오류 발생: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
CloseExcelObjects();
|
|
}
|
|
}
|
|
|
|
private void CloseExcelObjects()
|
|
{
|
|
if (workbook1 != null)
|
|
{
|
|
try { workbook1.Close(false); }
|
|
catch { }
|
|
}
|
|
if (excelApplication != null)
|
|
{
|
|
try { excelApplication.Quit(); }
|
|
catch { }
|
|
}
|
|
|
|
ReleaseExcelObjects();
|
|
}
|
|
|
|
private void ReleaseExcelObjects()
|
|
{
|
|
ReleaseComObject(titleBlockSheet);
|
|
ReleaseComObject(textEntitiesSheet);
|
|
ReleaseComObject(workbook1);
|
|
ReleaseComObject(excelApplication);
|
|
|
|
titleBlockSheet = null;
|
|
textEntitiesSheet = null;
|
|
workbook1 = null;
|
|
excelApplication = null;
|
|
}
|
|
|
|
private void ReleaseComObject(object obj)
|
|
{
|
|
try
|
|
{
|
|
if (obj != null && Marshal.IsComObject(obj))
|
|
{
|
|
Marshal.ReleaseComObject(obj);
|
|
}
|
|
}
|
|
catch (System.Exception)
|
|
{
|
|
// 해제 중 오류 발생 시 무시
|
|
}
|
|
finally
|
|
{
|
|
obj = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Layer ID로부터 Layer 이름을 가져옵니다.
|
|
/// </summary>
|
|
/// <param name="layerId">Layer ObjectId</param>
|
|
/// <param name="transaction">현재 트랜잭션</param>
|
|
/// <param name="database">데이터베이스 객체</param>
|
|
/// <returns>Layer 이름 또는 빈 문자열</returns>
|
|
private string GetLayerName(ObjectId layerId, Transaction transaction, Database database)
|
|
{
|
|
try
|
|
{
|
|
using (var layerTableRecord = transaction.GetObject(layerId, OpenMode.ForRead) as LayerTableRecord)
|
|
{
|
|
return layerTableRecord?.Name ?? "";
|
|
}
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Console.WriteLine($"Layer 이름 가져오기 오류: {ex.Message}");
|
|
return "";
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (excelApplication != null)
|
|
{
|
|
CloseExcelObjects();
|
|
}
|
|
|
|
if (appServices != null)
|
|
{
|
|
appServices.Dispose();
|
|
appServices = null;
|
|
}
|
|
}
|
|
}
|
|
}
|