원인은 경로에 섞인 슬래시였다. 폴더 칸에 C:/Users/... 처럼 슬래시가 섞인 값이 들어 있으면 Directory.Exists 는 통과시키지만, 대화상자의 InitialDirectory 는 윈도우 셸(COM)이 그대로 해석하다 ArgumentException 을 던진다. 그 예외는 대입할 때가 아니라 ShowDialog() 안쪽에서 올라오기 때문에 대입 줄만 try 로 감싸 둔 파일 비교 쪽도 똑같이 죽게 돼 있었다. - Services/PathUtil.cs 신설. 셸에 넘길 경로는 전부 여기를 거친다. - 폴더·파일 고르기 둘 다 ShowDialog() 를 감쌌다. 끊긴 네트워크 드라이브처럼 정규화로 걸러지지 않는 경우에는 시작 폴더 없이 한 번 더 연다. - 3차 작업 지시서와 진행 상황 문서 신설·갱신. 검사: PathTest 31건 신설(356 -> 387건). 실제 실행으로 왼쪽·오른쪽 폴더 10회 연속, 파일 비교의 기준·내 파일 각 1회 확인. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
86 lines
3.0 KiB
C#
86 lines
3.0 KiB
C#
using System;
|
|
using System.IO;
|
|
|
|
namespace MergeHub.Services
|
|
{
|
|
/// <summary>
|
|
/// 경로를 "윈도우 셸이 받아들이는 모양"으로 맞춰 주는 곳.
|
|
///
|
|
/// 왜 필요한가 - .NET 의 <see cref="Directory.Exists"/> 는 <c>C:/a/b</c> 처럼 슬래시를 섞어 써도
|
|
/// 통과시킨다. 그런데 파일 대화상자의 <c>InitialDirectory</c> 는 셸(COM)이 그대로 해석하고,
|
|
/// 슬래시가 섞인 경로를 받으면 <see cref="ArgumentException"/> 을 던진다.
|
|
/// 그 예외는 <c>ShowDialog()</c> 안쪽에서 올라오기 때문에 대입할 때 감싸 봐야 소용이 없고,
|
|
/// 잡지 않으면 프로그램이 그대로 죽는다(실제로 "왼쪽 폴더..." 를 누르면 죽던 원인이 이것이다).
|
|
///
|
|
/// 그래서 셸에 넘기는 경로는 반드시 여기를 거친다. 확인할 수 없는 경로는 빈 문자열이 되고,
|
|
/// 부르는 쪽은 그때 <c>InitialDirectory</c> 를 아예 지정하지 않으면 된다.
|
|
/// </summary>
|
|
public static class PathUtil
|
|
{
|
|
/// <summary>폴더 경로를 정규화한다. 실제로 있는 폴더가 아니면 빈 문자열.</summary>
|
|
public static string FullFolderPath(string? path)
|
|
{
|
|
var full = Normalize(path);
|
|
if (full.Length == 0) return string.Empty;
|
|
try
|
|
{
|
|
return Directory.Exists(full) ? full : string.Empty;
|
|
}
|
|
catch (IOException)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
/// <summary>파일 경로가 든 폴더를 정규화해서 돌려준다. 확인할 수 없으면 빈 문자열.</summary>
|
|
public static string FolderOfFile(string? filePath)
|
|
{
|
|
var full = Normalize(filePath);
|
|
if (full.Length == 0) return string.Empty;
|
|
|
|
try
|
|
{
|
|
return FullFolderPath(Path.GetDirectoryName(full));
|
|
}
|
|
catch (ArgumentException)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 구분자를 역슬래시로 맞추고 상대 경로를 절대 경로로 편다.
|
|
/// 경로로 쓸 수 없는 글자가 들어 있으면 빈 문자열.
|
|
/// </summary>
|
|
private static string Normalize(string? path)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(path)) return string.Empty;
|
|
|
|
try
|
|
{
|
|
return Path.GetFullPath(path!.Trim());
|
|
}
|
|
catch (ArgumentException)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
catch (NotSupportedException)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
catch (PathTooLongException)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
catch (IOException)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
}
|
|
}
|
|
}
|