성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>UWP 앱에서 FolderPicker 사용 시 유의 사항</h1> <p> UWP의 경우, 폴더 선택을 위한 대화 상자로 FolderPicker를 사용할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > FolderPicker Class ; <a target='tab' href='https://learn.microsoft.com/en-us/uwp/api/windows.storage.pickers.folderpicker'>https://learn.microsoft.com/en-us/uwp/api/windows.storage.pickers.folderpicker</a> </pre> <br /> 그런데 다음과 같이 사용하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > FolderPicker picker = new FolderPicker(); Windows.Storage.StorageFolder sfToLoad = await picker.PickSingleFolderAsync(); </pre> <br /> 실행 시, 이런 예외를 만날 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > - Exception <span style='color: blue; font-weight: bold'>{"Unspecified error\r\n"}</span> System.Exception {System.Runtime.InteropServices.COMException} _HResult -2147467259 int StackTrace " at Windows.Storage.Pickers.FolderPicker.PickSingleFolderAsync() at TestApp.MainPage.<Button_Click>d__1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_0(Object state) at System.Threading.WinRTSynchronizationContext.Invoker.InvokeCore()" </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Unhandled exception at 0x7509CFA1 (combase.dll) in TestApp.exe: 0xC000027B: An application-internal exception has occurred (parameters: 0x01018E50, 0x00000001). </pre> <br /> Visual Studio에서 디버깅하는 경우에는 다음의 코드에서 멈추게 되는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > #if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION UnhandledException += (sender, e) => { if (global::System.Diagnostics.Debugger.IsAttached) <span style='color: blue; font-weight: bold'>global::System.Diagnostics.Debugger.Break();</span> }; #endif </pre> <br /> 원인은 의외로 간단합니다. 바로, FileTypeFilter를 하나 이상 지정해야 한다는 점입니다. (그런데 이런 제약이 있다는 사실을 담은 문서를 찾을 수 없었습니다.)<br /> <br /> 어쨌든, 다음과 같이 코드 한 줄을 더 넣어야만 정상적으로 동작합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > FolderPicker picker = new FolderPicker(); <span style='color: blue; font-weight: bold'>picker.FileTypeFilter.Add("*");</span> Windows.Storage.StorageFolder sfToLoad = await picker.PickSingleFolderAsync(); </pre> <br /> 이 규칙은 FileOpenPicker / FileSavePicker에도 동일하게 적용됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> (FileOpenPicker / FileSavePicker를 포함해서) FolderPicker에는 재미있는 제약이 하나 더 있습니다. 바로 UWP 앱이 설치된 폴더(및 서브 폴더)를 제외한 컴퓨터 상의 모든 폴더는 기본적으로 접근할 수 없다는 점입니다. 방법이 있긴 한데 오직 "사용자가 선택"해야만 한다는 제약이 있습니다.<br /> <br /> 그래서, FolderPicker로 반환받은 StorageFolder 객체를 통해서만 다음과 같이 해당 폴더의 파일들을 열람할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Windows.Storage.StorageFolder sfToLoad = await picker.PickSingleFolderAsync(); var files = await sfToLoad.GetFilesAsync(); </pre> <br /> 반면, 이때 선택된 폴더 객체를 경로(Path)로 기억해 두었다가 나중에 재사용할 수는 없습니다. 가령 다음과 같은 식으로 코딩을 하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Windows.Storage.StorageFolder sfToLoad = await picker.PickSingleFolderAsync(); <span style='color: blue; font-weight: bold'>string path</span> = sfToLoad.Path; // 사용자가 선택한 폴더 // 아래의 코드는 예외 발생 Windows.Storage.StorageFolder sf = await Windows.Storage.StorageFolder.<span style='color: blue; font-weight: bold'>GetFolderFromPathAsync(path)</span>; </pre> <br /> 이런 예외가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > - Exception <span style='color: blue; font-weight: bold'>{"Access is denied.\r\n"}</span> System.Exception {System.UnauthorizedAccessException} _HResult -2147024891 int StackTrace " at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at TestApp.MainPage.<DisplayFile>d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_0(Object state) at System.Threading.WinRTSynchronizationContext.Invoker.InvokeCore()" </pre> <br /> 위의 오류 상황은 FileOpenPicker / FileSavePicker에도 동일하게 적용됩니다. 즉, 사용자가 선택한 후 반환받은 Windows.Storage.StorageFile 객체는 사용할 수 있지만 그 파일의 Path 경로를 보관했다가 나중에 접근하는 것은 허용되지 않습니다.<br /> <br /> 간단히 말해서, UWP 앱에서 전통적인 Windows File Path는 잊어버리는 것이 좋습니다.<br /> <br /> 그런데, 이런 제약은 사용자를 매우 불편하게 만듭니다. 가령, 이전에 설정한 작업 폴더가 있는 경우 다음번 UWP 앱을 실행시켰을 때 다시 한번 더 사용자가 FolderPicker를 통해 선택해 주어야 하기 때문입니다. 마이크로소프트는 이런 불편함을 없애기 위해 Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList 타입을 추가합니다.<br /> <br /> 그래서 사용자가 선택한 폴더를 MRU 목록에 추가한 다음 반환해 주는 토큰 값을 응용 프로그램이 기록해 두었다가,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>Windows.Storage.StorageFolder sfToLoad</span> = await picker.PickSingleFolderAsync(); string <span style='color: blue; font-weight: bold'>mruToken</span> = Windows.Storage.AccessCache.StorageApplicationPermissions.<span style='color: blue; font-weight: bold'>MostRecentlyUsedList.Add(sfToLoad);</span> Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings; <span style='color: blue; font-weight: bold'>localSettings.Values.Add("my_folder", mruToken);</span> // MRU 토큰 값을 기록 </pre> <br /> 다음번에 필요해서 해당 폴더를 "사용자 동의 없이" 접근하고 싶을 때 이렇게 사용할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > private async void Initialize() { Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings; if (localSettings.Values.ContainsKey("my_folder") == true) { <span style='color: blue; font-weight: bold'>string mruToken</span> = localSettings.Values["my_folder"] as string; <span style='color: blue; font-weight: bold'>Windows.Storage.StorageFolder sfToLoad = await Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList.GetFolderAsync(mruToken);</span> } } </pre> <br /> 즉, 전통적인 파일 경로 대신 토큰 값을 이용하도록 바뀌었다고 보면 됩니다. (참고로, MRU 목록에는 25개까지 보관할 수 있습니다.)<br /> <br /> 이와 관련된 좀 더 자세한 사항은 다음의 글에서 찾을 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Skip the path: stick to the StorageFile ; <a target='tab' href='https://learn.microsoft.com/en-us/archive/blogs/wsdevsol/skip-the-path-stick-to-the-storagefile'>https://learn.microsoft.com/en-us/archive/blogs/wsdevsol/skip-the-path-stick-to-the-storagefile</a> How to track recently used files and folders (HTML) ; <a target='tab' href='https://learn.microsoft.com/en-us/previous-versions/windows/apps/hh972603(v=win.10)'>https://learn.microsoft.com/en-us/previous-versions/windows/apps/hh972603(v=win.10)</a> </pre> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1131&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1113
(왼쪽의 숫자를 입력해야 합니다.)