teigha 오류 수정

This commit is contained in:
2025-07-22 10:45:51 +09:00
parent 5282927833
commit b13e981d04
7 changed files with 1244 additions and 86 deletions

View File

@@ -21,7 +21,7 @@ namespace DwgExtractorManual.Models
/// </summary>
internal class ExportExcel : IDisposable
{
// ODA 서비스 객체
// ODA 서비스 객체 (managed by singleton)
private Services appServices;
// Excel COM 객체들
@@ -72,7 +72,7 @@ namespace DwgExtractorManual.Models
}
Debug.WriteLine("🔄 ODA 초기화 중...");
ActivateAndInitializeODA();
InitializeTeighaServices();
Debug.WriteLine("🔄 Excel 초기화 중...");
InitializeExcel();
}
@@ -93,13 +93,20 @@ namespace DwgExtractorManual.Models
}
}
// ODA 제품 활성화 및 초기화
private void ActivateAndInitializeODA()
// Teigha 서비스 초기화 (싱글톤 사용)
private void InitializeTeighaServices()
{
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();
try
{
Debug.WriteLine("[DEBUG] TeighaServicesManager를 통한 Services 획득 중...");
appServices = TeighaServicesManager.Instance.AcquireServices();
Debug.WriteLine($"[DEBUG] Services 획득 성공. Reference Count: {TeighaServicesManager.Instance.ReferenceCount}");
}
catch (Teigha.Runtime.Exception ex)
{
Debug.WriteLine($"[DEBUG] Teigha Services 초기화 실패: {ex.Message}");
throw;
}
}
// Excel 애플리케이션 및 워크시트 초기화
@@ -603,14 +610,31 @@ namespace DwgExtractorManual.Models
return false;
}
// JSON 파일 읽기
string jsonContent = File.ReadAllText(jsonFilePath);
JObject jsonData = JObject.Parse(jsonContent);
// JSON 파일 읽기 및 정리
string jsonContent = File.ReadAllText(jsonFilePath, System.Text.Encoding.UTF8);
Debug.WriteLine($"[DEBUG] JSON 파일 크기: {jsonContent.Length} bytes");
// JSON 내용 정리 (주석 제거 등)
jsonContent = CleanJsonContent(jsonContent);
JObject jsonData;
try
{
jsonData = JObject.Parse(jsonContent);
}
catch (Newtonsoft.Json.JsonReaderException jsonEx)
{
Debug.WriteLine($"❌ JSON 파싱 오류: {jsonEx.Message}");
Debug.WriteLine($"❌ JSON 내용 미리보기 (첫 500자):");
Debug.WriteLine(jsonContent.Length > 500 ? jsonContent.Substring(0, 500) + "..." : jsonContent);
throw new System.Exception($"PDF 분석 JSON 파일 파싱 실패: {jsonEx.Message}\n파일: {jsonFilePath}");
}
var results = jsonData["results"] as JArray;
if (results == null)
{
Debug.WriteLine("❌ JSON에서 'results' 배열을 찾을 수 없습니다.");
Debug.WriteLine($"❌ JSON 루트 키들: {string.Join(", ", jsonData.Properties().Select(p => p.Name))}");
return false;
}
@@ -1032,7 +1056,21 @@ namespace DwgExtractorManual.Models
string jsonContent = File.ReadAllText(filePath, System.Text.Encoding.UTF8);
Debug.WriteLine($"[DEBUG] JSON 내용 길이: {jsonContent.Length}");
var deserializedData = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, JObject>>>(jsonContent);
// JSON 내용 정리 (주석 제거 등)
jsonContent = CleanJsonContent(jsonContent);
Dictionary<string, Dictionary<string, JObject>> deserializedData;
try
{
deserializedData = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, JObject>>>(jsonContent);
}
catch (Newtonsoft.Json.JsonReaderException jsonEx)
{
Debug.WriteLine($"❌ JSON 파싱 오류: {jsonEx.Message}");
Debug.WriteLine($"❌ JSON 내용 미리보기 (첫 500자):");
Debug.WriteLine(jsonContent.Length > 500 ? jsonContent.Substring(0, 500) + "..." : jsonContent);
throw new System.Exception($"매핑 JSON 파일 파싱 실패: {jsonEx.Message}\n파일: {filePath}");
}
// 새로운 딕셔너리 초기화
FileToMapkeyToLabelTagValuePdf.Clear();
@@ -1146,14 +1184,31 @@ namespace DwgExtractorManual.Models
return;
}
// JSON 파일 읽기
string jsonContent = File.ReadAllText(jsonFilePath);
JObject jsonData = JObject.Parse(jsonContent);
// JSON 파일 읽기 및 정리
string jsonContent = File.ReadAllText(jsonFilePath, System.Text.Encoding.UTF8);
Debug.WriteLine($"[DEBUG] JSON 파일 크기: {jsonContent.Length} bytes");
// JSON 내용 정리 (주석 제거 등)
jsonContent = CleanJsonContent(jsonContent);
JObject jsonData;
try
{
jsonData = JObject.Parse(jsonContent);
}
catch (Newtonsoft.Json.JsonReaderException jsonEx)
{
Debug.WriteLine($"❌ JSON 파싱 오류: {jsonEx.Message}");
Debug.WriteLine($"❌ JSON 내용 미리보기 (첫 500자):");
Debug.WriteLine(jsonContent.Length > 500 ? jsonContent.Substring(0, 500) + "..." : jsonContent);
throw new System.Exception($"PDF 분석 JSON 파일 파싱 실패: {jsonEx.Message}\n파일: {jsonFilePath}");
}
var results = jsonData["results"] as JArray;
if (results == null)
{
Debug.WriteLine("❌ JSON에서 'results' 배열을 찾을 수 없습니다.");
Debug.WriteLine($"❌ JSON 루트 키들: {string.Join(", ", jsonData.Properties().Select(p => p.Name))}");
return;
}
@@ -1229,17 +1284,158 @@ namespace DwgExtractorManual.Models
}
}
/// <summary>
/// JSON 내용을 정리하여 파싱 가능한 상태로 만듭니다.
/// 주석 제거 및 기타 무효한 문자 처리
/// </summary>
/// <param name="jsonContent">원본 JSON 내용</param>
/// <returns>정리된 JSON 내용</returns>
private string CleanJsonContent(string jsonContent)
{
if (string.IsNullOrEmpty(jsonContent))
return jsonContent;
try
{
// 줄별로 처리하여 주석 제거
var lines = jsonContent.Split('\n');
var cleanedLines = new List<string>();
bool inMultiLineComment = false;
foreach (string line in lines)
{
string processedLine = line;
// 멀티라인 주석 처리 (/* */)
if (inMultiLineComment)
{
int endIndex = processedLine.IndexOf("*/");
if (endIndex >= 0)
{
processedLine = processedLine.Substring(endIndex + 2);
inMultiLineComment = false;
}
else
{
continue; // 전체 라인이 주석
}
}
// 멀티라인 주석 시작 확인
int multiLineStart = processedLine.IndexOf("/*");
if (multiLineStart >= 0)
{
int multiLineEnd = processedLine.IndexOf("*/", multiLineStart + 2);
if (multiLineEnd >= 0)
{
// 같은 라인에서 시작하고 끝나는 주석
processedLine = processedLine.Substring(0, multiLineStart) +
processedLine.Substring(multiLineEnd + 2);
}
else
{
// 멀티라인 주석 시작
processedLine = processedLine.Substring(0, multiLineStart);
inMultiLineComment = true;
}
}
// 싱글라인 주석 제거 (//) - 문자열 내부의 //는 제외
bool inString = false;
bool escaped = false;
int commentIndex = -1;
for (int i = 0; i < processedLine.Length - 1; i++)
{
char current = processedLine[i];
char next = processedLine[i + 1];
if (escaped)
{
escaped = false;
continue;
}
if (current == '\\')
{
escaped = true;
continue;
}
if (current == '"')
{
inString = !inString;
continue;
}
if (!inString && current == '/' && next == '/')
{
commentIndex = i;
break;
}
}
if (commentIndex >= 0)
{
processedLine = processedLine.Substring(0, commentIndex);
}
// 빈 라인이 아니면 추가
if (!string.IsNullOrWhiteSpace(processedLine))
{
cleanedLines.Add(processedLine);
}
}
string result = string.Join("\n", cleanedLines);
Debug.WriteLine($"[DEBUG] JSON 정리 완료: {jsonContent.Length} -> {result.Length} bytes");
return result;
}
catch (System.Exception ex)
{
Debug.WriteLine($"❌ JSON 정리 중 오류: {ex.Message}");
// 정리 실패시 원본 반환
return jsonContent;
}
}
public void Dispose()
{
if (excelApplication != null)
try
{
CloseExcelObjects();
}
Debug.WriteLine("[DEBUG] ExportExcel Dispose 시작");
if (excelApplication != null)
{
Debug.WriteLine("[DEBUG] Excel 객체 정리 중...");
CloseExcelObjects();
}
if (appServices != null)
if (appServices != null)
{
Debug.WriteLine("[DEBUG] Teigha Services 해제 중...");
try
{
TeighaServicesManager.Instance.ReleaseServices();
Debug.WriteLine($"[DEBUG] Teigha Services 해제 완료. Remaining ref count: {TeighaServicesManager.Instance.ReferenceCount}");
}
catch (System.Exception ex)
{
Debug.WriteLine($"[DEBUG] Teigha Services 해제 중 오류 (무시됨): {ex.Message}");
}
finally
{
appServices = null;
}
}
Debug.WriteLine("[DEBUG] ExportExcel Dispose 완료");
}
catch (System.Exception ex)
{
appServices.Dispose();
appServices = null;
Debug.WriteLine($"[DEBUG] ExportExcel Dispose 중 전역 오류: {ex.Message}");
// Disposal 오류는 로그만 남기고 계속 진행
}
}
}

View File

@@ -15,15 +15,22 @@ namespace DwgExtractorManual.Models
/// </summary>
internal sealed class SqlDatas : IDisposable
{
Services appServices; // ODA 제품 활성화용
Services appServices; // ODA 제품 활성화용 (managed by singleton)
readonly string connectionString = "Host=localhost;Database=postgres;Username=postgres;Password=Qwer1234";
void ActivateAndInitializeODA()
void InitializeTeighaServices()
{
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();
try
{
Debug.WriteLine("[SqlDatas] TeighaServicesManager를 통한 Services 획득 중...");
appServices = TeighaServicesManager.Instance.AcquireServices();
Debug.WriteLine($"[SqlDatas] Services 획득 성공. Reference Count: {TeighaServicesManager.Instance.ReferenceCount}");
}
catch (Teigha.Runtime.Exception ex)
{
Debug.WriteLine($"[SqlDatas] Teigha Services 초기화 실패: {ex.Message}");
throw;
}
}
void CreateTables()
@@ -78,7 +85,7 @@ namespace DwgExtractorManual.Models
public SqlDatas()
{
ActivateAndInitializeODA();
InitializeTeighaServices();
CreateTables();
}
@@ -301,8 +308,20 @@ namespace DwgExtractorManual.Models
{
if (appServices != null)
{
appServices.Dispose();
appServices = null;
try
{
Debug.WriteLine("[SqlDatas] Teigha Services 해제 중...");
TeighaServicesManager.Instance.ReleaseServices();
Debug.WriteLine($"[SqlDatas] Teigha Services 해제 완료. Remaining ref count: {TeighaServicesManager.Instance.ReferenceCount}");
}
catch (Teigha.Runtime.Exception ex)
{
Debug.WriteLine($"[SqlDatas] Teigha Services 해제 중 오류 (무시됨): {ex.Message}");
}
finally
{
appServices = null;
}
}
}
}

View File

@@ -0,0 +1,192 @@
using System;
using System.Diagnostics;
using Teigha.Runtime;
namespace DwgExtractorManual.Models
{
/// <summary>
/// Singleton class to manage Teigha Services lifecycle and prevent disposal conflicts
/// </summary>
public sealed class TeighaServicesManager
{
private static readonly object _lock = new object();
private static TeighaServicesManager _instance = null;
private static Services _services = null;
private static int _referenceCount = 0;
private static bool _isActivated = false;
private TeighaServicesManager()
{
// Private constructor for singleton
}
public static TeighaServicesManager Instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null)
{
_instance = new TeighaServicesManager();
}
}
}
return _instance;
}
}
/// <summary>
/// Acquires Teigha Services (creates if needed, increments reference count)
/// </summary>
/// <returns>The Services instance</returns>
public Services AcquireServices()
{
lock (_lock)
{
try
{
Debug.WriteLine($"[TeighaManager] AcquireServices - Current ref count: {_referenceCount}");
if (!_isActivated)
{
Debug.WriteLine("[TeighaManager] Activating ODA for first time...");
ActivateODA();
_isActivated = true;
}
if (_services == null)
{
Debug.WriteLine("[TeighaManager] Creating new Services instance...");
_services = new Services();
Debug.WriteLine("[TeighaManager] Services instance created successfully");
}
_referenceCount++;
Debug.WriteLine($"[TeighaManager] Services acquired - New ref count: {_referenceCount}");
return _services;
}
catch (Teigha.Runtime.Exception ex)
{
Debug.WriteLine($"[TeighaManager] Error acquiring services: {ex.Message}");
throw;
}
}
}
/// <summary>
/// Releases Teigha Services (decrements reference count, disposes when count reaches 0)
/// </summary>
public void ReleaseServices()
{
lock (_lock)
{
try
{
Debug.WriteLine($"[TeighaManager] ReleaseServices - Current ref count: {_referenceCount}");
if (_referenceCount > 0)
{
_referenceCount--;
Debug.WriteLine($"[TeighaManager] Services released - New ref count: {_referenceCount}");
}
// Don't dispose Services until app shutdown to prevent conflicts
// Just track reference count for debugging
if (_referenceCount == 0)
{
Debug.WriteLine("[TeighaManager] All references released (Services kept alive for app lifetime)");
}
}
catch (Teigha.Runtime.Exception ex)
{
Debug.WriteLine($"[TeighaManager] Error releasing services: {ex.Message}");
// Don't throw on release to prevent cascade failures
}
}
}
/// <summary>
/// Force dispose Services (only call on application shutdown)
/// </summary>
public void ForceDisposeServices()
{
lock (_lock)
{
try
{
Debug.WriteLine("[TeighaManager] Force disposing Services...");
if (_services != null)
{
_services.Dispose();
Debug.WriteLine("[TeighaManager] Services disposed successfully");
}
_services = null;
_referenceCount = 0;
_isActivated = false;
Debug.WriteLine("[TeighaManager] Force dispose completed");
}
catch (Teigha.Runtime.Exception ex)
{
Debug.WriteLine($"[TeighaManager] Error during force dispose: {ex.Message}");
// Reset state even if disposal fails
_services = null;
_referenceCount = 0;
_isActivated = false;
}
}
}
/// <summary>
/// Get current reference count (for debugging)
/// </summary>
public int ReferenceCount
{
get
{
lock (_lock)
{
return _referenceCount;
}
}
}
/// <summary>
/// Check if Services is active and valid
/// </summary>
public bool IsServicesActive
{
get
{
lock (_lock)
{
return _services != null && _isActivated;
}
}
}
private void ActivateODA()
{
try
{
Debug.WriteLine("[TeighaManager] Activating ODA...");
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);
Debug.WriteLine("[TeighaManager] ODA activation successful");
}
catch (Teigha.Runtime.Exception ex)
{
Debug.WriteLine($"[TeighaManager] ODA activation failed: {ex.Message}");
throw;
}
}
}
}