성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
글쓰기
제목
이름
암호
전자우편
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'>C# - (파일) 확장자와 연결된 실행 파일 경로 찾기</h1> <p> 다음과 같은 질문이 있군요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 파일 확장자명을 이용해 파일의 실행 프로그램의 전체 경로를 얻어 올 수 있을까요? ; <a target='tab' href='http://www.sysnet.pe.kr/3/0/4874'>http://www.sysnet.pe.kr/3/0/4874</a> </pre> <br /> 질문에서 언급한 ProgramAssociationInfo 타입은 닷넷 기본 BCL에 포함된 것은 아닙니다. 그렇다면 누군가 만들었다는 것인데 BCL에는 없으니까 만들었겠죠? ^^<br /> <br /> 암튼, File Association과 관련한 모든 정보는 레지스트리에 있습니다. 따라서 이런 경우 Win32 API의 힘을 빌릴 수 있습니다. 검색해 보면, 이에 대해 FindExecutable이 있다고 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Is an Application Associated With a Given Extension? ; <a target='tab' href='https://stackoverflow.com/questions/9540051/is-an-application-associated-with-a-given-extension'>https://stackoverflow.com/questions/9540051/is-an-application-associated-with-a-given-extension</a> </pre> <br /> C#으로는 다음과 같이 코딩할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [DllImport("shell32.dll")] public static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult); FileAssociation.FindExecutable(@"C:\temp\test.txt", string.Empty, sb); </pre> <br /> 근데, 문제는 실제 파일이 있어야만 동작하기 때문에 확장자만으로 찾을 수 없습니다. 게다가 일부 파일에 대해서만 가능한데... 기준을 잘 모르겠습니다. 가령 c:\temp 폴더에 있는 test.cs 파일을 지정했는데 이에 대해서는 비주얼 스튜디오에 대한 경로가 아닌 빈 문자열을 반환합니다.<br /> <br /> 자... 그럼 그다음으로 생각할 수 있는 것이 바로 AssocQueryString win32 API입니다. 사용법은 다음과 같이 마련해 주고,<br /> <br /> <pre style='height: 400px; margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Runtime.InteropServices; using System.Text; namespace ConsoleApp1 { class FileAssociation { [DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] static unsafe extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, ref uint pcchOut); [DllImport("shell32.dll")] public static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult); public unsafe static void ListAssociationInfo(string extension) { StringBuilder sb = new StringBuilder(1024); foreach (string name in Enum.GetNames(typeof(AssocStr))) { uint cchOut = 1024 / 2; AssocStr value = (AssocStr)Enum.Parse(typeof(AssocStr), name); uint result = AssocQueryString(AssocF.None, value, extension, null, sb, ref cchOut); Console.Write(name + " == "); if (result == 0) { Console.Write(sb.ToString()); } // 0x80070483 == No application is associated with the specified file for this operation. Console.WriteLine(); } } } [Flags] enum AssocF : uint { None = 0, Init_NoRemapCLSID = 0x1, Init_ByExeName = 0x2, Open_ByExeName = 0x2, Init_DefaultToStar = 0x4, Init_DefaultToFolder = 0x8, NoUserSettings = 0x10, NoTruncate = 0x20, Verify = 0x40, RemapRunDll = 0x80, NoFixUps = 0x100, IgnoreBaseClass = 0x200, Init_IgnoreUnknown = 0x400, Init_FixedProgId = 0x800, IsProtocol = 0x1000, InitForFile = 0x2000, } enum AssocStr { Command = 1, Executable, FriendlyDocName, FriendlyAppName, NoOpen, ShellNewValue, DDECommand, DDEIfExec, DDEApplication, DDETopic, InfoTip, QuickTip, TileInfo, ContentType, DefaultIcon, ShellExtension, DropTarget, DelegateExecute, SupportedUriProtocols, Max, } } </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;' > FileAssociation.ListAssociationInfo(@".pdf"); </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;' > <span style='color: blue; font-weight: bold'>Command == "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" "%1" Executable == C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe</span> FriendlyDocName == Adobe Acrobat Document FriendlyAppName == Adobe Acrobat Reader DC NoOpen == ShellNewValue == DDECommand == DDEIfExec == DDEApplication == AcroRd32 DDETopic == System InfoTip == prop:System.ItemTypeText;System.Size;<a target='tab' href='https://devblogs.microsoft.com/oldnewthing/20230921-00/?p=108808'>System.DateModified</a> QuickTip == prop:System.ItemTypeText;System.Size;System.DateModified TileInfo == prop:System.ItemTypeText;System.Size;System.DateModified ContentType == application/pdf DefaultIcon == C:\Windows\Installer\{AC76BA86-7AD7-1042-7B44-AC0F074E4100}\PDFFile_8.ico,0 ShellExtension == DropTarget == DelegateExecute == SupportedUriProtocols == file: Max == AcroExch.Document.DC </pre> <br /> 대충 Executable이 맞을 것 같은데요. 반면 ".cs" 확장자로 해보니 다음과 같은 결과가 나옵니다.<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'>Command == "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe" /dde</span> Executable == FriendlyDocName == Visual C# Source file FriendlyAppName == NoOpen == ShellNewValue == DDECommand == Open("%1") DDEIfExec == DDEApplication == VisualStudio.14.0 DDETopic == system InfoTip == prop:System.ItemTypeText;System.Size;System.DateModified QuickTip == prop:System.ItemTypeText;System.Size;System.DateModified TileInfo == prop:System.ItemTypeText;System.Size;System.DateModified ContentType == text/plain DefaultIcon == C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC#\VCSPackages\csproj.dll,1 ShellExtension == DropTarget == DelegateExecute == SupportedUriProtocols == file: Max == VisualStudio.cs.14.0 </pre> <br /> 따라서 확률을 좀 더 높이려면 Command의 문자열을 가져와 exe 경로만을 분리해서 구하는 것이 더 좋을 것 같습니다.<br /> <br /> 하나 더 테스트해볼까요? ^^ ".mp3"로 했더니 이런 결과가 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Command == Executable == FriendlyDocName == MP3 File FriendlyAppName == Groove 음악 NoOpen == ShellNewValue == DDECommand == DDEIfExec == DDEApplication == DDETopic == System InfoTip == prop:System.ItemType;System.Size;System.Music.Artist;System.Media.Duration;System.OfflineAvailability QuickTip == prop:System.ItemTypeText;System.Size;System.DateModified TileInfo == prop:System.ItemTypeText;System.Size;System.DateModified ContentType == audio/mpeg DefaultIcon == @{Microsoft.ZuneMusic_10.17062.14111.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.ZuneMusic/Files/Assets/FileExtension.png} ShellExtension == DropTarget == <span style='color: blue; font-weight: bold'>DelegateExecute == {4ED3A719-CEA8-4BD9-910D-E252F997AFC2}</span> SupportedUriProtocols == *: Max == AppXqj98qxeaynz6dv4459ayz6bnqxbyaqcs </pre> <br /> Command와 Executable이 아예 비어 있습니다. 대신 눈에 띄는 것이 있다면 DelegateExecute인데요, 해당 GUID 값으로 레지스트리를 검색해 보니 다음의 정보가 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [HKEY_CLASSES_ROOT\CLSID\{4ED3A719-CEA8-4BD9-910D-E252F997AFC2}] @="Association Launch Execute Command" [HKEY_CLASSES_ROOT\CLSID\{4ED3A719-CEA8-4BD9-910D-E252F997AFC2}\InProcServer32] @="%SystemRoot%\system32\twinui.dll" "ThreadingModel"="Apartment" [HKEY_CLASSES_ROOT\CLSID\{4ED3A719-CEA8-4BD9-910D-E252F997AFC2}\SupportedProtocols] @="*" </pre> <br /> "Association Launch Execute Command"라는데, 재미있는 것은 제 컴퓨터에는 .mp3를 실행하면 Windows Store 앱 중에서 Groove 음악 플레이어가 뜬다는 점입니다. 아마도 Store App으로 연결된 확장자들은 "4ED3A719-CEA8-4BD9-910D-E252F997AFC2" 핸들러가 중계 처리해 주는 것이 아닌가 싶습니다. 실제로 레지스트리의 "HKEY_CLASSES_ROOT\.mp3" 항목을 봐도 실행 파일에 대한 정보는 찾을 수 없었습니다.<br /> <br /> 이런 식으로 못 가져오는 경우가 종종 있습니다. 가령 .sln 파일의 경우 Visual Studio는 다중 버전을 고려한 Visual Studio Version Selector로 연결되어 있고 그 프로그램이 .sln 파일의 내용에 따라 어느 버전의 비주얼 스튜디오인지 판단해서 그 버전의 devenv.exe를 실행합니다. 따라서, 특정 확장자로 바로 연결된 EXE를 찾는 것은 쉽지 않은 일입니다.<br /> <br /> 그래도 이 정도면, 특수한 경우를 제외하고는 제법 방법이 나온 것 같군요. ^^<br /> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1163&boardid=331301885'>첨부한 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1810
(왼쪽의 숫자를 입력해야 합니다.)