Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

(시리즈 글이 3개 있습니다.)
디버깅 기술: 57. C# - double 값에 대한 windbg 확인
; https://www.sysnet.pe.kr/2/0/1526

디버깅 기술: 97. windbg - 메모리 덤프로부터 DateTime 형식의 값을 알아내는 방법
; https://www.sysnet.pe.kr/2/0/11313

디버깅 기술: 202. windbg - ASP.NET MVC Web Application (.NET Framework) 응용 프로그램의 덤프 분석 시 요령
; https://www.sysnet.pe.kr/2/0/13741




windbg - ASP.NET MVC Web Application (.NET Framework) 응용 프로그램의 덤프 분석 시 요령

ASP.NET Web Application (.NET Framework) 응용 프로그램을 MVC 유형으로 기본 예제를 하나 만들어 windbg로 분석하는 과정 중에 나오는 것들을 정리해 보겠습니다.

우선, 개발자 입장에서 (MVC) 웹 사이트의 소스 코드 구조는 이렇게 나옵니다.

/Controllers/HomeController.cs
        Indxe()
        About() 
        Contact()

/Views/Home
        /About.cshtml
        /Contact.cshtml
        /Index.cshtml

그리고 이것을 빌드하면 WebApplication1.dll DLL 파일 하나에 해당 웹 프로젝트의 모든 소스코드 컴파일 결과물이 포함됩니다. 이후, WebApplication1.dll을 디컴파일해 보면 개발자가 작성한 (HomeController.cs 등의) Controller 코드는 모두 (특별히 변경하지 않았다면) "Controllers" 네임스페이스 하위에서 찾을 수 있습니다.

WebApplication1.Controllers
    HomeController
        About()
        Contact()
        Index()

반면 cshtml 파일의 경우에는 다소 특별한데요, 개발자가 ASP.NET Web App을 개발한 다음, publish를 하게 되면 기본적으로 다음과 같은 식으로 결과물이 나옵니다.

/ (루트 디렉터리)
    [bin]
    [Content]
    favicon.ico
    Global.asax
    [Scripts]
    [Views] // cshtml 파일이 놓인 디렉터리 
    Web.config

따라서 운영 중인 서버에서 디버깅을 하는 중이라면 WebApp의 배포 디렉터리에서 cshtml 파일의 원본을 찾을 수 있습니다. 하지만, 프로세스의 덤프 파일에서는 저 원본 내용을 찾을 수 없습니다.

왜냐하면, ASP.NET 엔진은 런타임 시에 cshtml 파일을 pre-compile 시켜 DLL로 만들어 놓은 다음 사용하기 때문에 덤프 파일 내에는 어떠한 cshtml 파일의 내용도 찾을 수 없습니다. (물론, 운 좋게 ASP.NET 엔진이 컴파일을 위해 string 변수에 담은 파일 내용을 GC되기 전에 찾을 수 있다면 가능할 수도 있습니다.)




ASP.NET 엔진은 cshtml 파일에 대한 요청이 오면 그 순간 cshtml 파일을 pre-compile 시켜 DLL 파일로 만들어 놓습니다. 그리고 그 결과물은 호스팅 중인 서버의 "%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files" 경로에 cache합니다.

물론, 메모리 덤프를 뜬 경우에는 그 DLL들이 모두 덤프 파일에 담기게 됩니다.

그렇다면 혹시 덤프에 포함된 그 pre-compiled 시킨 DLL을 디컴파일하면 cshtml 파일의 내용을 볼 수 있을까요? 아쉽게도 cshtml 파일의 원본은 확인할 수 없습니다. lm 명령어로 DLL 목록을 볼 때 "App_Web_[...hash...].dll" 유형의 이름을 갖는 것들이 바로 cshtml 파일의 내용을 포함하고 있는 DLL인데요,

0:000> lm
start             end                 module name
...[생략]...
00000233`4b3e0000 00000233`4b3e8000   App_Web_esgmt44v   (deferred)             
00000233`4b3f0000 00000233`4b3fa000   App_Web_bauo0udd   (deferred)       
...[생략]...

파일명의 나머지 부분이 여러 가지 조건을 기반으로 한 hash로 이뤄지기 때문에 어떤 cshtml 파일인지 파일명만으로는 판단할 수 없습니다. 결국 일일이 decompiler로 열어봐야 하는데, 이것도 매우 번거로운 일이므로 Reflection을 이용해 검색을 할 수 있는 유틸리티를 만들어 사용하는 것이 좋을 것입니다.

참고로, About.cshtml 파일의 컴파일 결과물을 보면 다음과 같이 나오는데요, (일일이 열어본 결과 App_Web_esgmt44v.dll에 있었습니다.)

using System;
using System.Runtime.CompilerServices;
using System.Web.Mvc;
using Microsoft.CSharp.RuntimeBinder;

namespace ASP
{
    // Token: 0x02000004 RID: 4
    [Dynamic(new bool[]
    {
        false,
        true
    })]
    public class _Page_Views_Home_About_cshtml : WebViewPage<object>
    {
        // Token: 0x17000002 RID: 2
        // (get) Token: 0x06000009 RID: 9 RVA: 0x00002300 File Offset: 0x00000500
        protected global_asax ApplicationInstance
        {
            get
            {
                return (global_asax)this.Context.ApplicationInstance;
            }
        }

        // Token: 0x0600000A RID: 10 RVA: 0x00002324 File Offset: 0x00000524
        public override void Execute()
        {
            if (_Page_Views_Home_About_cshtml.<>o__3.<>p__0 == null)
            {
                _Page_Views_Home_About_cshtml.<>o__3.<>p__0 = CallSite<Func<CallSite, object, string, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, "Title", typeof(_Page_Views_Home_About_cshtml), new CSharpArgumentInfo[]
                {
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.Constant, null)
                }));
            }
            _Page_Views_Home_About_cshtml.<>o__3.<>p__0.Target(_Page_Views_Home_About_cshtml.<>o__3.<>p__0, base.ViewBag, "About");
            this.WriteLiteral("\r\n<main");
            this.WriteLiteral(" aria-labelledby=\"title\"");
            this.WriteLiteral(">\r\n    <h2");
            this.WriteLiteral(" id=\"title\"");
            this.WriteLiteral(">");
            if (_Page_Views_Home_About_cshtml.<>o__3.<>p__2 == null)
            {
                _Page_Views_Home_About_cshtml.<>o__3.<>p__2 = CallSite<Action<CallSite, _Page_Views_Home_About_cshtml, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.InvokeSimpleName | CSharpBinderFlags.ResultDiscarded, "Write", null, typeof(_Page_Views_Home_About_cshtml), new CSharpArgumentInfo[]
                {
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
                }));
            }
            Action<CallSite, _Page_Views_Home_About_cshtml, object> target = _Page_Views_Home_About_cshtml.<>o__3.<>p__2.Target;
            CallSite <>p__ = _Page_Views_Home_About_cshtml.<>o__3.<>p__2;
            if (_Page_Views_Home_About_cshtml.<>o__3.<>p__1 == null)
            {
                _Page_Views_Home_About_cshtml.<>o__3.<>p__1 = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "Title", typeof(_Page_Views_Home_About_cshtml), new CSharpArgumentInfo[]
                {
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
                }));
            }
            target(<>p__, this, _Page_Views_Home_About_cshtml.<>o__3.<>p__1.Target(_Page_Views_Home_About_cshtml.<>o__3.<>p__1, base.ViewBag));
            this.WriteLiteral(".</h2>\r\n    <h3>");
            if (_Page_Views_Home_About_cshtml.<>o__3.<>p__4 == null)
            {
                _Page_Views_Home_About_cshtml.<>o__3.<>p__4 = CallSite<Action<CallSite, _Page_Views_Home_About_cshtml, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.InvokeSimpleName | CSharpBinderFlags.ResultDiscarded, "Write", null, typeof(_Page_Views_Home_About_cshtml), new CSharpArgumentInfo[]
                {
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
                }));
            }
            Action<CallSite, _Page_Views_Home_About_cshtml, object> target2 = _Page_Views_Home_About_cshtml.<>o__3.<>p__4.Target;
            CallSite <>p__2 = _Page_Views_Home_About_cshtml.<>o__3.<>p__4;
            if (_Page_Views_Home_About_cshtml.<>o__3.<>p__3 == null)
            {
                _Page_Views_Home_About_cshtml.<>o__3.<>p__3 = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "Message", typeof(_Page_Views_Home_About_cshtml), new CSharpArgumentInfo[]
                {
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
                }));
            }
            target2(<>p__2, this, _Page_Views_Home_About_cshtml.<>o__3.<>p__3.Target(_Page_Views_Home_About_cshtml.<>o__3.<>p__3, base.ViewBag));
            this.WriteLiteral("</h3>\r\n\r\n    <p>Use this area to provide additional information.</p>\r\n</main>");
        }
    }
}

cshtml 원본에서는 ViewBag.Title = "About" 코드 한 줄이,

@{
    ViewBag.Title = "About";
}
<main aria-labelledby="title">
    <h2 id="title">@ViewBag.Title.</h2>
    <h3>@ViewBag.Message</h3>

    <p>Use this area to provide additional information.</p>
</main>

다음과 같이 dynamic 유형으로 변환돼 복잡하게 디컴파일이 됩니다.

if (_Page_Views_Home_About_cshtml.<>o__3.<>p__0 == null)
{
    _Page_Views_Home_About_cshtml.<>o__3.<>p__0 = CallSite<Func<CallSite, object, string, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, "Title", typeof(_Page_Views_Home_About_cshtml), new CSharpArgumentInfo[]
    {
        CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
        CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.Constant, null)
    }));
}
_Page_Views_Home_About_cshtml.<>o__3.<>p__0.Target(_Page_Views_Home_About_cshtml.<>o__3.<>p__0, base.ViewBag, "About");

그러니까, 저런 코드 조각들이 나오면 중간에 @{...} 코드 블록으로 인해 추가된 것으로 인지할 수 있습니다. 현실적인 기준으로, 저 코드를 통해 뭔가 원인 추적을 하는 것은 그다지 도움이 되지 않을 것입니다.




따라서 디버깅 측면에서 봤을 때, cshtml 파일에 코드를 넣어두기보다는 기왕이면 Controller 측에 넣어두는 것이 더 좋습니다.

자, 그럼 Controller 측의 코드로 다시 돌아가 예를 들기 위해 일부러 지연 코드를 넣어두고,

public ActionResult Index()
{
    Thread.Sleep(1000 * 60);
    return View();
}

실제로 실행된 프로세스의 덤프를 Debug Analysis로 분석해 보면 이런 결과가 나옵니다.

HttpContext Report

HttpContext Timeout Completed   RunningSince    ThreadId    ReturnCode  Verb    RequestPath+QueryString
24b41371328 110 Sec Yes     --- 200 GET /
24c813713c8 110 Sec Yes     --- 200 GET /Home/About
24d81804348 110 Sec Yes     --- 200 GET /Home/Contact
24d8188a608 110 Sec No  11 Sec  52  200 GET /

저기서, Completed가 Yes인 것들은 이미 HTTP 요청이 완료된 상태로 단지 GC Heap에 HttpContext 인스턴스가 아직 (수거되지 않고) 남아 있어 보여주는 것에 불과합니다.

따라서 실제로 의미가 있는 것은 현재 수행 중인 HttpContext == 24d8188a608, ThreadId == 52 항목을 살펴볼 필요가 있는데요, Windbg에서 52번 스레드로 이동해 call stack을 확인할 수 있으므로,

// 사실, callstack 마저도 기본적으로 Debug Analysis에서 제공해 줍니다.

0:000> ~52s
ntdll!NtDelayExecution+0x14:
00007ffa`cee307b4 c3              ret

0:052> !clrstack
OS Thread Id: 0xd2ac (52)
        Child SP               IP Call Site
0000005753d7d138 00007ffacee307b4 [HelperMethodFrame: 0000005753d7d138] System.Threading.Thread.SleepInternal(Int32)
0000005753d7d230 00007ffaa603b0bb System.Threading.Thread.Sleep(Int32) [f:\dd\ndp\clr\src\BCL\system\threading\thread.cs @ 725]
0000005753d7d260 00007ffa523e70d7 WebApplication1.Controllers.HomeController.Index() [c:\temp\webapp\WebApplication1\WebApplication1\Controllers\HomeController.cs @ 14]
0000005753d7d2a0 00007ffa525100d7 DynamicClass.lambda_method(System.Runtime.CompilerServices.Closure, System.Web.Mvc.ControllerBase, System.Object[])
0000005753d7d2d0 00007ffa523e68e3 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionDescriptor, System.Collections.Generic.IDictionary`2<System.String,System.Object>)
...[생략]...
0000005753d7e700 00007ff987baee84 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
0000005753d7e740 00007ff9882615e3 DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)
0000005753d7e908 00007ffab16dfef3 [ContextTransitionFrame: 0000005753d7e908] 

문제 분석에 도움이 될 수 있습니다. 아울러, HttpContext 개체 자체도 덤프해 볼 수 있는데요,

0:052> !do 24d8188a608
Name:        System.Web.HttpContext
MethodTable: 00007ff98788fdd8
EEClass:     00007ff9879564e0
Size:        424(0x1a8) bytes
File:        C:\WINDOWS\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ff98788f5d0  4000334        8 ...IHttpAsyncHandler  0 instance 0000000000000000 _asyncAppHandler
00007ff987886be0  4000335      160         System.Int32  1 instance                0 _asyncPreloadModeFlags
00007ffaa5adc638  4000336      170       System.Boolean  1 instance                1 _asyncPreloadModeFlagsSet
00007ff98788de70  4000337       10 ...b.HttpApplication  0 instance 0000024b41373de0 _appInstance
00007ff98788f638  4000338       18 ....Web.IHttpHandler  0 instance 0000024d8188ddc0 _handler
00007ff98788fef0  4000339       20 ...m.Web.HttpRequest  0 instance 0000024d8188a7c8 _request
00007ff98788ff98  400033a       28 ....Web.HttpResponse  0 instance 0000024d8188a950 _response
...[생략]...

개인적인 경험으로는 딱히 의미 있었던 적은 없었습니다. (종종 특별하게는, 가령 HttpContext.Items에 넣어둔 데이터를 확인하는 게 필요하다면!)

참고로, 시간 되시면 이 글도 한번 읽어보시고. ^^

Debugging Script: Dumping out current and recent ASP.NET Requests
; https://www.tessferrandez.com/blog/2007/09/12/debugging-script-dumping-out-current-and-recent-aspnet-requests.html




다른 경우로, 예외 발생 상황을 볼까요? 테스트를 위해 관련 코드를 추가하고,

public ActionResult Index()
{
    try
    {
        throw new InvalidCastException("[Index] test exception");
    } catch { }
    return View();
}

public ActionResult About()
{
    ViewBag.Message = "Your application description page.";

    throw new InvalidCastException("[About] test exception");
    return View();
}

우선, About을 방문해서 발생하는 예외라면 ASP.NET의 경우 기본적으로 Event Viewer에서 호출 스택까지도 자세하게 남겨주므로,

Event code: 3005 
...[생략]...
Event detail code: 0 
 
Application information: 
    Application domain: /LM/W3SVC/2/ROOT-1-133717210099867290 
    Trust level: Full 
    Application Virtual Path: / 
    Application Path: C:\temp\webapp\WebApplication1\WebApplication1\ 
    Machine name: KEVIN10 
 
Process information: 
    Process ID: 13400 
    Process name: w3wp.exe 
    Account name: IIS APPPOOL\tempweb 
 
Exception information: 
    Exception type: InvalidCastException 
    Exception message: [About] test exception
   at WebApplication1.Controllers.HomeController.About() in c:\temp\webapp\WebApplication1\WebApplication1\Controllers\HomeController.cs:line 26
   at lambda_method(Closure , ControllerBase , Object[] )
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   ...[생략]...

 
Request information: 
    Request URL: http://localhost:8030/Home/About 
    Request path: /Home/About 
    User host address: ::1 
    User:  
    Is authenticated: False 
    Authentication Type:  
    Thread account name: IIS APPPOOL\tempweb 
 
Thread information: 
    Thread ID: 10 
    Thread account name: IIS APPPOOL\tempweb 
    Is impersonating: False 
    Stack trace:    at WebApplication1.Controllers.HomeController.About() in c:\temp\webapp\WebApplication1\WebApplication1\Controllers\HomeController.cs:line 26
   at lambda_method(Closure , ControllerBase , Object[] )
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   ...[생략]...
 

그나마 쉽게 분석이 가능합니다. 문제는, 예외를 먹는 Index에서의 경우입니다. 이럴 때는 방문을 해도 Event Viewer에도 남지 않는데요, 만약 저 결과로 인해 사용자가 원하는 화면이 나오지 않는 경우 그 원인을 추적하기가 매우 힘든 상황이 됩니다. 이럴 때는, procdump를 이용해 볼 수 있는데요,

try/catch로 조용히 사라진 예외를 파악하고 싶다면?
; https://www.sysnet.pe.kr/2/0/10965

따라서 다음과 같이 실행해 두고,

// 관리자 권한으로 실행
// w3wp.exe의 pid == 13400인 경우,

C:\Windows\System32> procdump -e 1 -f "" 13400
...[생략]...

예외를 먹는 페이지를 방문하면 그 순간 화면에 다음과 같은 출력이 나옵니다.

[16:06:39] Exception: E0434F4D.System.InvalidCastException ("[Index] test exception")

그럼, Ctrl+C 키를 눌러 procdump를 종료하고 위에서 얻은 예외 타입으로 덤프를 뜨도록 다음과 같이 다시 실행합니다.

// 관리자 권한으로 실행
// w3wp.exe의 pid == 13400인 경우,

C:\Windows\System32> procdump -ma  -e 1 -f System.InvalidCastException 13400
...[생략]...

이후 문제가 되는 페이지를 방문하면 예외가 발생하는 그 순간 덤프가 남겨지고, 그 덤프를 통해 문제의 원인을 추적할 수 있습니다.

0:043> !clrstack
OS Thread Id: 0x3974 (43)
        Child SP               IP Call Site
000000684e67da78 00007ffacee301b4 [HelperMethodFrame: 000000684e67da78] 
000000684e67db60 00007ffa523e711e WebApplication1.Controllers.HomeController.Index() [c:\temp\webapp\WebApplication1\WebApplication1\Controllers\HomeController.cs @ 16]
000000684e67dbd0 00007ffa525100d7 DynamicClass.lambda_method(System.Runtime.CompilerServices.Closure, System.Web.Mvc.ControllerBase, System.Object[])
000000684e67dc00 00007ffa523e68e3 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionDescriptor, System.Collections.Generic.IDictionary`2<System.String,System.Object>)
...[생략]...

물론, 이 모든 것들은 Remote Debugging이 허용되는 상황이라면 덤프 없이 라이브 디버깅을 하는 것이 훨씬 문제 분석을 쉽게 할 수 있습니다. ^^






[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 9/25/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 121  122  123  124  125  126  127  128  129  130  131  [132]  133  134  135  ...
NoWriterDateCnt.TitleFile(s)
1755정성태9/22/201434251오류 유형: 241. Unity Web Player를 설치해도 여전히 설치하라는 화면이 나오는 경우 [4]
1754정성태9/22/201424575VC++: 80. 내 컴퓨터에서 C++ AMP 코드가 실행이 될까요? [1]
1753정성태9/22/201420600오류 유형: 240. Lync로 세미나 참여 시 소리만 들리지 않는 경우 [1]
1752정성태9/21/201441059Windows: 100. 윈도우 8 - RDP 연결을 이용해 VNC처럼 사용자 로그온 화면을 공유하는 방법 [5]
1751정성태9/20/201438917.NET Framework: 464. 프로세스 간 통신 시 소켓 필요 없이 간단하게 Pipe를 열어 통신하는 방법 [1]파일 다운로드1
1750정성태9/20/201423827.NET Framework: 463. PInvoke 호출을 이용한 비동기 파일 작업파일 다운로드1
1749정성태9/20/201423730.NET Framework: 462. 커널 객체를 위한 null DACL 생성 방법파일 다운로드1
1748정성태9/19/201425379개발 환경 구성: 238. [Synergy] 여러 컴퓨터에서 키보드, 마우스 공유
1747정성태9/19/201428391오류 유형: 239. psexec 실행 오류 - The system cannot find the file specified.
1746정성태9/18/201426076.NET Framework: 461. .NET EXE 파일을 닷넷 프레임워크 버전에 상관없이 실행할 수 있을까요? - 두 번째 이야기 [6]파일 다운로드1
1745정성태9/17/201423032개발 환경 구성: 237. 리눅스 Integration Services 버전 업그레이드 하는 방법 [1]
1744정성태9/17/201431035.NET Framework: 460. GetTickCount / GetTickCount64와 0x7FFE0000 주솟값 [4]파일 다운로드1
1743정성태9/16/201420983오류 유형: 238. 설치 오류 - Failed to get size of pseudo bundle
1742정성태8/27/201426947개발 환경 구성: 236. Hyper-V에 설치한 리눅스 VM의 VHD 크기 늘리는 방법 [2]
1741정성태8/26/201421329.NET Framework: 459. GetModuleHandleEx로 알아보는 .NET 메서드의 DLL 모듈 관계파일 다운로드1
1740정성태8/25/201432496.NET Framework: 458. 닷넷 GC가 순환 참조를 해제할 수 있을까요? [2]파일 다운로드1
1739정성태8/24/201426490.NET Framework: 457. 교착상태(Dead-lock) 해결 방법 - Lock Leveling [2]파일 다운로드1
1738정성태8/23/201422040.NET Framework: 456. C# - CAS를 이용한 Lock 래퍼 클래스파일 다운로드1
1737정성태8/20/201419742VS.NET IDE: 93. Visual Studio 2013 동기화 문제
1736정성태8/19/201425565VC++: 79. [부연] CAS Lock 알고리즘은 과연 빠른가? [2]파일 다운로드1
1735정성태8/19/201418149.NET Framework: 455. 닷넷 사용자 정의 예외 클래스의 최소 구현 코드 - 두 번째 이야기
1734정성태8/13/201419805오류 유형: 237. Windows Media Player cannot access the file. The file might be in use, you might not have access to the computer where the file is stored, or your proxy settings might not be correct.
1733정성태8/13/201426331.NET Framework: 454. EmptyWorkingSet Win32 API를 사용하는 C# 예제파일 다운로드1
1732정성태8/13/201434455Windows: 99. INetCache 폴더가 다르게 보이는 이유
1731정성태8/11/201427054개발 환경 구성: 235. 점(.)으로 시작하는 파일명을 탐색기에서 만드는 방법
1730정성태8/11/201422144개발 환경 구성: 234. Royal TS의 터미널(Terminal) 연결에서 한글이 깨지는 현상 해결 방법
... 121  122  123  124  125  126  127  128  129  130  131  [132]  133  134  135  ...