성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Reordering on an Alpha processor ;...
[정성태] 공유 감사합니다. ^^ 참고로, WPF에서 WindowsF...
[Tom Lee] 답변 감사합니다. 나름의 해결책 연구해보고 여기에도 공유해봅니다...
[정성태] 아래의 글을 보면, MoveWindow 하면 될 듯한데요. ^^...
[Tom Lee] 안녕하세요 올려주신 글 참고하여 WPF 어플리케이션 안에 Uni...
[정성태] A graphical depiction of the steps ...
[정성태] 질문을 주셔서 출판사 측에 문의를 했습니다. 약 한 달 정도 후...
[Thorondor
] @정성태 개인 블로그인데도 거의 커뮤니티 급 인 것 같아요. 요...
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <div style='font-family: 맑은 고딕, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>Apache Module에 대한 'F5 디버그 (Start with debugging)'</div> <br /> 역시, 디버깅은 Visual Studio IDE 내에서 "F5 (Start with debugging)" 키를 이용한 디버깅이 되어야 생산성이 급격히 높아지죠. "Apache Module" 개발에 대해서도 물론 그렇게 할 수 있습니다.<br /> <br /> 사실, 방법도 그리 어렵지 않은데요. 지난번 IDE 내에서의 컴파일에 이어서 계속 이야기를 진행해 보겠습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > 윈도우에서 Apache Module 컴파일 (VC++) ; <a target='_tab' href='http://www.sysnet.pe.kr/2/0/1051'>http://www.sysnet.pe.kr/2/0/1051</a> </pre> <br /> 컴파일된 결과물이 mod_example.so라는 DLL 형식이기 때문에 "F5" 키를 이용하여 디버깅하려면 우선, EXE 파일 지정이 필요합니다. 당연히 아파치 실행파일인 httpd.exe가 이에 해당할테니, 다음과 같이 프로젝트 속성 창 화면에서 httpd.exe 경로를 지정해 줍니다.<br /> <br /> <img alt='how_to_debug_module_handler_1.png' src='/SysWebRes/bbs/how_to_debug_module_handler_1.png' /><br /> <br /> 그다음, 빌드된 결과물이 곧바로 반영되어 아파치에 올라가야 할 테니 출력 폴더를 apache의 module 폴더로 해주면 됩니다.<br /> <br /> <img alt='how_to_debug_module_handler_2.png' src='/SysWebRes/bbs/how_to_debug_module_handler_2.png' /><br /> <br /> 일단은, 우리가 아는 지식대로라면 이 정도면 정상적으로 'F5 디버깅'이 가능해야 합니다. x_register_hooks 함수와 x_handler 함수에 BP(BreakPoint)를 걸고 'F5' 키를 누르면 httpd.exe 프로세스가 시작되면서 x_register_hooks 함수에서 정상적으로 BP가 동작하는 것을 확인할 수 있습니다.<br /> <br /> 그런데, 아쉽게도 x_handler 함수에서는 멈추지 않습니다. <br /> <br /> <hr style='width: 50%' /><br /> <br /> x_handler에서 멈추지 않는 이유가 뭘까요? 아파치는 httpd.exe 프로세스를 부모/자식 관계로 실행합니다. 예전의 IIS 5와 비교하자면 inetinfo.exe와 aspnet_wp.exe로 나뉜 것과 비슷한 예입니다. 그리고, Visual Studio는 'F5 디버깅' 시에 첫 번째 프로세스에 대해서만 디버깅을 하고 있으며 그 프로세스가 생성한 2차(자식) 프로세스에는 디버깅 기능을 제공하지 않습니다. 이 때문에, 실제적인 요청을 처리하는 2차 httpd.exe 프로세스에서 실행되는 x_handler 함수의 BP가 동작하지 않는 것입니다.<br /> <br /> 이렇게 되면, x_handler를 디버깅하기 위해서는 실행 후에 디버거를 붙이는 수밖에는 없어 보이는데요. 물론, 그렇게 하면 'F5 디버깅'과는 비교할 수 없는 생산성 차이가 납니다.<br /> <br /> 뭐 좋은 방법이 없을까요? ^^<br /> <br /> 다행히, 지난번에 써둔 글이 생각나는군요. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > 보호 모드로 응용 프로그램 디버깅하는 방법 ; <a target='_tab' href='http://www.sysnet.pe.kr/2/0/682'>http://www.sysnet.pe.kr/2/0/682</a> 보호 모드로 응용 프로그램 디버깅하는 방법 - 두 번째 이야기 ; <a target='_tab' href='http://www.sysnet.pe.kr/2/0/683'>http://www.sysnet.pe.kr/2/0/683</a> </pre> <br /> 아하~~~ ^^ 매크로를 이용하면 됩니다. 일단, 현재 "<a target='_tab' href='http://www.sysnet.pe.kr/2/0/683<br /> '>보호 모드로 응용 프로그램 디버깅하는 방법 - 두 번째 이야기</a>" 글에 정리된 매크로를 그대로 가져다가 httpd.exe 모듈 디버깅에 사용하면 다음과 같은 오류가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > <b style='COLOR: blue'>httpd.exe: System.Runtime.InteropServices.COMException (0x800704DF): An attempt was made to perform an initialization operation when initialization has already been completed. </b> at Microsoft.VisualBasic.CompilerServices.LateBinding.InternalLateCall(Object o, Type objType, String name, Object[] args, String[] paramnames, Boolean[] CopyBack, Boolean IgnoreReturn) at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateCall(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack, Boolean IgnoreReturn) at MyMacros.F5Debug.OnEventArrived(Object sender, EventArrivedEventArgs e) in vsmacros://...[생략].../MyMacros/MyMacros.vsmacros/F5Debug:line 98 </pre> <br /> 원인은, 그 매크로가 부모 자식이 모두 동일한 이름으로 실행되는 경우에 대한 배려가 없기 때문입니다. 이 때문에 이미 Visual Studio가 디버깅하고 있는 부모 httpd.exe 프로세스를 다시 "Process.Attach()" 하려고 시도하는 경우가 발생해서 "An attempt was made to perform an initialization operation when <b style='COLOR: blue'>initialization has already been completed</b>."와 같은 오류 메시지를 내는 것입니다.<br /> <br /> 그래서 이런 문제를 보완한 다음의 매크로 소스 코드를 가져다 사용하시면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Imports System Imports EnvDTE Imports EnvDTE80 Imports EnvDTE90 Imports System.Diagnostics Imports System.Management Public Module F5Debug Public Sub RunAndAttachTo() DTE.Solution.SolutionBuild.Build(True) DTE.Solution.SolutionBuild.Debug() AttachTo() End Sub Dim f_watcher As ManagementEventWatcher Public Sub AttachTo() Dim pol As String pol = "1" Dim queryString As String queryString = "SELECT *" & _ " FROM __InstanceOperationEvent " & _ "WITHIN " & pol & _ " WHERE TargetInstance ISA 'Win32_Process'" Dim scope As String scope = "\\.\root\CIMV2" If (f_watcher Is Nothing) Then Else f_watcher.Stop() f_watcher = Nothing End If f_watcher = New ManagementEventWatcher(scope, queryString) ' 새로 생성되는 프로세스를 감시한다. AddHandler f_watcher.EventArrived, AddressOf OnEventArrived f_watcher.Start() End Sub Private Sub OnEventArrived(ByVal sender As Object, _ ByVal e As EventArrivedEventArgs) Dim rootWatcher As ManagementEventWatcher rootWatcher = sender Dim debuggeeProcessId As Integer Dim processes As EnvDTE.Processes processes = DTE.Debugger.DebuggedProcesses ' 1차 디버깅 프로세스의 ID를 구한다. ' 즉 psexec.exe의 ID를 구한다. If (processes.Count <> 0) Then For Each procDebuggee As EnvDTE.Process In processes debuggeeProcessId = procDebuggee.ProcessID Next End If If (debuggeeProcessId = 0) Then Exit Sub End If ' 새로 생성된 프로세스의 부모 프로세스 ID를 구한다. ' 즉 현재 주 디버기 process의 하위에 생성된 프로세스를 구별해 낸다. Dim parentProcessIdOfnewProcess As Integer Dim targetInstance As ManagementBaseObject Dim processId As Integer targetInstance = e.NewEvent.Properties("TargetInstance").Value parentProcessIdOfnewProcess = targetInstance.Properties("ParentProcessId").Value processId = targetInstance.Properties("ProcessID").Value If (parentProcessIdOfnewProcess = debuggeeProcessId) Then rootWatcher.Stop() Dim newProcessName As String newProcessName = targetInstance.Properties("Name").Value.ToString() For Each proc In DTE.Debugger.LocalProcesses Dim proc3 As EnvDTE90.Process3 proc3 = proc If (proc3.ProcessID = processId) Then Try proc.Attach() Debug.Print(newProcessName & ": Attached successfully!") Catch x As Exception Debug.Print(newProcessName & ": " & x.ToString()) Finally End Try Exit For End If Next End If End Sub End Module </pre> <br /> 위의 매크로를 이제 "<a target='_tab' href='http://www.sysnet.pe.kr/2/0/682'>보호 모드로 응용 프로그램 디버깅하는 방법</a>" 글에서 설명한 것처럼 특정 단축키에 할당하거나 툴바에 새로운 아이콘으로 등록해서 편하게 사용할 수 있습니다. 제 경우에는 "Shift + F2" 키로 할당해 두었고, 아파치 모듈 프로젝트에서 "Shift + F2" 조합을 눌러 다음과 같이 디버깅 상태로 진입하는 것이 가능했습니다.<br /> <br /> <img alt='how_to_debug_module_handler_3.png' src='/SysWebRes/bbs/how_to_debug_module_handler_3.png' /><br /> <br /> 오히려, 주의해야 할 것은 종료 과정입니다. 전통적으로 "Shift + F5 (Stop Debugging)" 키를 누르면 현재 디버깅 중인 프로세스를 빠져나오게 되는데요. 이렇게 하면 부모/자식 관계로 생성되는 아파치의 경우에는 부모 프로세스만 종료되고 자식 프로세스가 살아 남아 다음번 아파치 프로그램 실행 시에 부모 프로세스가 초기화 도중 그냥 종료를 해버립니다.<br /> <br /> 이런 문제를 방지하기 위해서는 "Shift + F5" 키를 눌러 디버깅 세션을 빠져나오면 안되고, 반드시 현재 실행 중인 아파치 콘솔을 종료해 주어야 합니다. (만약 "Shift + F5" 키를 누른 경우라면, 작업 관리자에서 남아 있는 httpd.exe 프로세스를 직접 종료시켜야 합니다.)<br /> <br /> 어쨌든, 이제 남은 것은 Visual Studio에서 인텔리센스와 F5(Shift + F2)에 해당하는 디버깅 기능을 이용하여 아파치 모듈을 좀 더 쉽게 개발하는 일이겠죠.<br /> <br /> (다들... 이렇게 개발하고 있는 거 맞죠? 설마... printf 문 찍으면서 디버깅하고 있는 거 아니죠? ^^)<br /> <br /><br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
7964
(왼쪽의 숫자를 입력해야 합니다.)