Serach

2014년 5월 29일 목요일

CentOS에서 httpd UserDir 사용시 권한 문제 해결 방법

디렉토리 권한 설정이나 httpd.conf 설정에도 문제가 없는데..
httpd.conf에서 사용자별 디렉토리 설정은 활성화 되어있었고,
사용자 홈 디렉토리의 권한은 711,
public_html의 권한 역시 755로 잘 잡혀 있는데..
않된다.... 403 !!!!  Forbidden   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
하아................................


문제는 CentOS의 SELinux boolean 값이다.
터미널에서 아래 명령어로 값을 확인해 보자.


getsebool -a | grep httpd_enable_homedirs


httpd_enable_homedirs --> off


off 상태면 httpd.conf 에서 사용자별 디렉토리를 설정했더라도 막상 접속해보면 퍼미션 오류가 나타게 된다. 
httpd_enable_homedirs 를 on 해주면 httpd의 사용자별 디렉토리 권한 문제가 해결된다.


setsebool -P httpd_enable_homedirs on


끝 ...

2014년 4월 6일 일요일

CentOS apache 세팅

CentOS에선 apache가 네트워크를 사용하는걸 막아 놨습니다.



간단한 옵션 설정으로 네트워크를 사용하게 할 수 있습니다.


getsebool -a | grep 'httpd'


우선 옵션 확인.

[root@localhost /]# getsebool -a | grep 'httpd'

allow_httpd_anon_write --> off
allow_httpd_mod_auth_ntlm_winbind --> off
allow_httpd_mod_auth_pam --> off
allow_httpd_sys_script_anon_write --> off
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_network_connect --> off
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
httpd_can_network_memcache --> off
httpd_can_network_relay --> off
httpd_can_sendmail --> off
httpd_dbus_avahi --> on
httpd_enable_cgi --> on
httpd_enable_ftp_server --> off
httpd_enable_homedirs --> off
httpd_execmem --> off
httpd_manage_ipa --> off
httpd_read_user_content --> off
httpd_run_stickshift --> off
httpd_setrlimit --> off
httpd_ssi_exec --> off
httpd_tmp_exec --> off
httpd_tty_comm --> on
httpd_unified --> on
httpd_use_cifs --> off
httpd_use_gpg --> off
httpd_use_nfs --> off
httpd_use_openstack --> off
httpd_verify_dns --> off

httpd_can_network_connect 옵션을  on으로 설정

setsebool -P httpd_can_network_connect on






http://gshan85.tistory.com/66



2014년 3월 12일 수요일

SP 변경 이력 추적 쉽게 하기


오랜만에 블로그에 글을 쓰네요..

sql server 데이터베이스 작업중

SP가 빈번히 변경되는데 변경 이력 추적이 어려울때 사용하면 좋은 방법입니다.

물론 소스 관리 툴을 쓰는게 가장 좋은것 같고..

가장 간편하게 적용 할 수 있는 쿼리 입니다.

변경 이력을 추적할 데이터 베이스에서 해당 쿼리를 실행합니다.


CREATE TABLE dbo.SPLOG(
idx int IDENTITY(1,1) NOT NULL,
sp_name varchar(100) NULL,
division varchar(20) NULL,
SQLCMD varchar(max) NULL,
author varchar(20) NULL,
modified_date datetime NULL,
 CONSTRAINT XPKSPLOG PRIMARY KEY NONCLUSTERED
(
idx ASC
))

GO


먼저 위의 쿼리로 변경이력을 저장할 테이블을 만듭니다.




CREATE TRIGGER TRG_SPLOG ON DATABASE
FOR
CREATE_PROCEDURE, ALTER_PROCEDURE, DROP_PROCEDURE,
CREATE_VIEW, ALTER_VIEW, DROP_VIEW,
CREATE_FUNCTION, ALTER_FUNCTION, DROP_FUNCTION,
CREATE_TRIGGER, ALTER_TRIGGER, DROP_TRIGGER

AS

DECLARE @DATA XML

SET @DATA = EVENTDATA()

INSERT INTO DBO.SPLOG (sp_name, division, SQLCMD, author, modified_date)
VALUES
(@DATA.value('(/EVENT_INSTANCE/ObjectName)[1]', 'VARCHAR(100)'),
 @DATA.value('(/EVENT_INSTANCE/EventType)[1]', 'VARCHAR(100)'),
 @DATA.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'VARCHAR(MAX)'),
 HOST_NAME(),
 GETDATE())

다음은 위의 쿼리로 데이터베이스 트리거를 등록합니다.


트리거 등록 후에는 프로시저, 뷰, 펑션, 트리거를 만들거나 수정, 지우게 될 경우

이력이 SPLOG 테이블에 남게 됩니다.


2014년 1월 20일 월요일

Transaction-Level Read Consistency (트랜잭션 수준 읽기 일관성)

트랜잭션 수준 읽기 일관성이란?


문장수준 읽기 일관성(Statement-Level Read Consistency)
  • 쿼리가 시작된 시점을 기준으로 데이터를 일관성 있게 읽어 들이는 것

트랜잭션 수준 읽기 일관성(Transaction-Level Read Consistency)
  • 트랜잭션이 시작된 시점을 기준으로 일관성 있게 데이터를 읽어 들이는 것



이상 현상 3가지


  • Dirty Read ( = Uncommitted Dependency )
          커밋되지 않은 수정 중인 데이터를 다른 트랜잭션에서 읽을 수 있도록 허용할때 발생
          대부분 DBMS가 기본 트랜잭션 고립화 수준을 레벨1 로 설정하고 있어 Dirty Read는 발생하지 않음
          =  커밋된 데이터만 읽을 수 있도록 허용
          SQL Server, Sybase등은 데이터를 읽을 때 공유 Lock을 사용,
          갱신중인 레코드에는 배타적 Lock이 걸림, 
          이는 공유 Lock과는 호환되지 않아 갱신중인 레코드는 읽지 못함(Lock에 의한 동시성 저하 발생)
  • Non-Repeatable Read ( = Inconsistent Analysis )
          한 트랜잭션 내에서 같은 쿼리를 두번 수행할 때 그 사이에 다른 트랜잭션이 값을 수정 또는 삭제함으로써
          두 쿼리의 결과가 상이하게 나타나는 비일관성이 발생하는 것을 말함
  • Phantom Read 
          한 트랜잭션 안에서 일정 범위의 레코드를 두번 이상 읽을 때, 
          첫번째 쿼리에서 없던 레코드가 두번째 쿼리에서 나타나는 현상
          이는 트랜잭션 도중 새로운 레코드가 삽입되는 것을 허용하기 때문에 나타나는 현상.



이상현상은 트랜잭션 수준 읽기 일관성(Transaction-Level Read Consistency)때문에 생기는 현상이며
고립화 수준을 조정함으로써 해결 할 수 있다.
하지만 고립화 수준을 높이면 데이터 일관성은 확보 되지만 동시성이 현격히 저하되는 결과를 초래 할 수 있다.


Transaction Isolation Level


트랜잭션 수준으로 읽기 일관성을 강화 하려면 트랜잭션 고립화 수준을 높여 주어야 한다. 
트랜잭션 고립화 수준을 조절하는 방법은 네가지 수준이 있다.
ANSI / ISO SQL standard(SQL92)에서 정의함

■ 레벨 0 ( = Read Uncommitted )
 - 트랜잭션에서 처리중인 / 아직
커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용
 - Dirty Read, Non-repeatable Read, Phantom Read 현상 발생

■ 레벨 1 ( = Read Committed )
 - Dirty Read 방지 :
트랜잭션이 커밋되어 확정된 데이터만 읽는 것을 허용
 -
대부분의 DBMS가 기본모드로 채택하고 있는 일관성 모드
 - Non-Repeatable Read, Phantom Read 현상 발생

■ 레벨 2 ( = Repeatable Read )
 - 선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때까지
후행 트랜잭션이 갱신하거나 삭제하는 것을 불허함으로써 같은 데이터를 두번 쿼리했을 때 일관성 있는 결과를 리턴
 - Phantom Read 현상 발생

■ 레벨 3 ( = Serializable Read )
 - 선행 트랜잭션이 읽은 데이터를 후행 트랜잭션이 갱신하거나 삭제하지 못할 뿐만 아니라 중간에 새로운 레코드를 삽입하는 것도 막아줌
 -
완벽한 읽기 일관성 모드를 제공

2014년 1월 10일 금요일

실용주의 프로그래머 TIP

1. 자신의 기술craft에 관심과 애정을 가져라
소프트웨어 개발을 잘 해보려는 생각이 없다면 왜 인생을 그 일을 하면서 보내는가?

2. 자신의 일에 대해 생각하면서 일하라!
자동 조종 장치를 끄고 직접 조종하라. 스스로의 작업을 지속적으로 비판하고 평가하라.

3. 어설픈 변명을 만들지 말고 대안을 제시하라.
변명하는 대신 대안을 제시하라.
그 일은 할 수 없다고 말하지 말고, 무엇을 할 수 있는지에 대해 설명하라.

4. 깨진 창문들 내버려두지 말라.
눈에 뜨일 때마다 나쁜 설계, 잘못된 결정, 좋지 않은 코드를 고쳐라.

5. 변화의 촉매가 되라.
사람들에게 변화를 강요할 수는 없다.
대신, 미래가 어떤 모습일지 그들에게 보여주고 미래를 만드는 일에
그들이 참여하도록 도우라.

6. 큰 그림을 기억하라.
주변에 무슨 일이 일어나는지 점검하는 일을 잊어버릴 정도로 세부사항에 빠지지 말라.

7. 품질을 요구사항으로 만들어라.
프로젝트의 진짜 품질 요구사항을 결정하는 자리에 사용자를 참여시켜라.

8. 지식 포트폴리오에 주기적으로 투자하라.
학습을 습관으로 만들어라.

9. 읽고 듣는 것을 비판적으로 분석하라.
벤더, 매체들의 야단법석, 도그마에 흔들리지 말라.
여러분과 여러분 프로젝트의 관점에서 정보를 분석하라.

10. 무엇을 말하는가와 어떻게 말하는가 모두 중요하다. .
효과적으로 전달하지 못한다면 좋은 생각이 있어봐야 소용없다.

11. DRY-반복하지 마라 Don't Repeat Yourself
어떤 지식 한 조각도 하나의 시스템 안에서는 모호하지 않고, 권위 있고,
단 하나뿐인 표현을 가져야 한다.

12. 재사용하기 쉽게 만들라.
재사용하기 쉽다면, 사람들이 재사용할 것이다. 재사용을 촉진하는 환경을 만들라.

13. 관련 없는 것들 간에 서로 영향이 없도록 하라.
컴포넌트를 자족적이고, 독립적이며, 단 하나의 잘 정의된 목적만 갖도록 설계하라.

14. 최종 결정이란 없다.
돌에 새겨진 것처럼 불변하는 결정은 없다. 그렇게 생각하는 대신,
모든 결정이 해변의 백사장 위에 쓴 글자와 같다고 생각하고 변화에 대비하라.

15. 목표물을 찾기 위해 예광탄을 써라.
예광탄은 이것저것을 시도해보고
그것들이 목표와 얼마나 가까운 데 떨어지는지 보는 방법으로 목표를 정확히 맞추게 해준다.

16. 프로토타입을 통해 학습하라.
프로토타이핑은 배움의 경험이다.
프로토타이핑의 가치는 만들어낸 코드에 있지 않고, 여러분이 배운 교훈에 있다.

17. 문제 도메인에 가깝게 프로그래밍 하라.
사용자의 언어를 사용해서 설계와 코딩을 하라.

18. 추정을 통해 놀람을 피하라.
시작하기 전에 추정부터 하라.  잠재적인 문제점들을 미리 찾아내게 될 것이다.

19. 코드와 함께 일정도 반복하며 조정하라.
구현하면서 얻는 경험을 이용해서 프로젝트의 시간 척도를 세밀히 조정하라.

20. 지식을 일반 텍스트로 저장하라.
일반 텍스트 형식은 시일이 지났다고 못쓰게 되는 일이 없다.
일반 텍스트 형식은 여러분의 작업을 활용하고 디버깅과
테스팅을 쉽게 만드는 데 도움이 된다.

21. 명령어 셸의 힘을 사용하라.
그래픽 사용자 인터페이스로는 할 수 없는 일에 셸을 이용하라.

22. 하나의 에디터를 잘 사용하라.
에디터를 마치 손의 연장으로 자유자재로 다루어야 한다.
여러분이 사용하는 에디터는 설정을 바꿀 수 있고, 확장 가능 하고, 프로그램 가능해야 한다.

23. 언제나 소스코드 관리 시스템을 사용하라.
소스코드 관리는 여러분 작업을 위한 타임머신이다.
언제라도 과거로 돌아갈 수 있게 해준다.

24. 비난 대신 문제를 해결하라.
버그가 여러분 잘못인지 다른 사람 잘못인지는 별로 중요하지 않다.
그것은 여전히 여러분의 문제이며, 여전히 고쳐야 할 필요가 있다.

25. 디버깅을 할 때 당황하지 마라.
숨을 깊게 들이 쉬고, 무엇이 버그를 일으키는지 "생각하라!"

26. Select는 망가지지 않았다.
OS나 컴파일러의 버그를 발견하는 일은 정말 드물게 일어나며,
심지어 써드파티 제품이나 라이브러리일지라도 드문 일이다.
버그는 애플리케이션에 있을 가능성이 가장 크다.

27. 가정하지 마라. 증명하라.
진짜 데이터와 경계 조건이 있는 실제 환경에서 여러분이 내렸던 가정들을 증명하라.

28. 텍스트 처리 언어를 하나 익혀라.
여러분은 하루 가운데 많은 시간을 텍스트와 씨름하며 보낸다.
왜 여러분 대신 컴퓨터가 그 일의 일부를 하게끔 만들지 않는가?

29. 코드를 작성하는 코드를 작성하라.
코드 생성기는 생산성을 증가시키며 중복을 막는 일에도 도움이 된다.

30. 완벽한 소프트웨어는 만들 수 없다.
소프트웨어는 완벽할 수 없다.
피할 수 없이 나타나는 에러로부터 여러분의 코드와 사용자들을 보호하라.

31. 계약에 따른 설계를 하라.
코드가 실제로 하기로 한 것을 문서화하고 검증하기 위해 계약을 사용하라.

32. 일찍 작동을 멈추게 하라.
보통은 죽은 프로그램이 절름발이 프로그램보다 해를 훨씬 덜 끼친다.

33. 단정문을 사용해서 불가능한 상황을 예방하라.
단정은 여러분이 세운 가정을 검증해준다.
확실한 것이 없는 세상에서 여러분의 코드를 보호하려면 단정문을 사용하라.

34. 예외는 예외적인 문제에 사용하라.
예외를 잘못 쓰면 고전적 스파게티 코드의 모든 가독성과 유지보수 문제를
그대로 겪을지도 모른다. 예외는 예외적인 일들만을 위해 남겨두어라.

34. 시작한 것은 끝내라.
가능하다면, 리소스를 할당한 루틴이나 객체가 해제도 책임져야 한다.

36. 모듈간의 결합도를 최소화 하라.
디미터 법칙을 적용하고 "부끄럼 타는" 코드를 작성해서 결합이 생기는 일을 피하라.

37. 통합하지 말고 설정하라.
애플리케이션에서 기술 선택을 설정 옵션으로 구현하고, 통합하거나 만들어 넣지 말라.

38. 코드에는 추상화를, 메타데이터에는 세부 내용을.
프로그램은 최대한 일반화해서 만들고,
세부사항들은 가능하면 컴파일된 코드 기반 바깥으로 빼라.

39. 작업흐름 분석을 통해 동시성을 개선하라.
사용자의 작업흐름이 허용하는 동시성을 최대한 활용하라.

40. 서비스를 사용해서 설계하라.
서비스, 곧 잘 정의되고 일관성 있는 인터페이스를 통해 의사소통하는
독립적이고 동시성 있는 객체들의 관점에서 설계하라.

41. 언제나 동시성을 고려해 설계하라.
동시성이 가능하도록 설계하면, 더 적은 가정만 내리고서도 더 깔끔한 설계를 할 수 있다.

42. 모델에서 뷰를 분리하라.
애플리케이션을 모델과 뷰의 관점으로 설계해서 적은 비용만 들이고도 유연함을 얻어내라.

43. 칠판을 사용해 작업흐름을 조율하라.
참여하는 요소들의 독립성과 고립성을 유지하면서도
개별적인 사실과 에이전트를 잘 조율하려면 칠판을 사용하라.

44. 우연에 맡기는 프로그래밍을 하지 말라.
정말 믿을 만한 것만 믿어야 한다.
우발적인 복잡함을 조심하고, 우연한 행운을 목적의식을 가지고 만든 계획과 착각하지 말라.

45. 여러분의 알고리즘의 차수를 추정하라.
코드를 작성하기 전에, 실행 시간이 대략 얼마나 걸릴지 감을 잡아 놓아라.

46. 여러분의 추정을 테스트하라.
알고리즘의 수학적 분석이 모든 것을 다 알려주지는 않는다.
실제 대상 환경에서 코드의 수행 시간을 측정해 보라.

47. 일찍 리팩토링하고, 자주 리팩토링하라.
정원의 잡초를 뽑고 식물 배치를 조정하는 것과 똑같이,
코드도 필요할 때면 언제라도 다시 작성하고, 다시 작업하고 다시 아키텍쳐를 만들라.
문제의 근원을 해결하라.

48 테스트를 염두에 두고 설계하라.
코드를 한 줄이라도 쓰기 전에 테스팅에 대해 생각하기 시작해야 한다.

49. 소프트웨어를 테스트하라. 그렇지 않으면 사용자가 테스트하게 될 것이다.
가차 없이 테스트하라. 사용자가 여러분을 위해 버그를 찾게 만들지 말라.

50. 자신이 이해하지 못하는, 마법사가 만들어준 코드는 사용하지 마라.
마법사는 엄청난 양의 코드를 만들 수 있다.
그것들을 프로젝트에 통합해 넣기 전에 그 코드 내용을 전부 이해하는지
확실히 해놓도록 하라.

51. 요구사항을 수집하지 말고 채굴하라.
요구사항이 지면에 놓여져 있는 경우는 퍽 드물다.
보통은 가정과 오해, 정치의 지층들 속 깊이 묻혀 있다.

52. 사용자처럼 생각하기 위해 사용자와 함께 일하라.
시스템이 정말로 어떻게 사용될지 통찰력을 얻을 수 있는 가장 좋은 방법이다.

53. 구체적인 것보다 추상적인 것이 더 오래간다.
구현 말고 추상에 투자하라.
추상은 서로 다른 구현이나 새로운 기술의 출현 때문에
빗발치듯 생기는 변화를 견뎌내고 살아남을 수 있다.

54. 프로젝트 용어사전을 사용하라.
프로젝트에서 쓰이는 특정 용어와 어휘들의 유일한 출처를 만들고 유지하라.

55. 생각의 틀을 벗어나지 말고, 틀을 찾아라.
해결이 불가능해 보이는 문제와 마주 쳤을 때, 진짜 제약 조건을 찾아라.
스스로에게 이렇게 물어보라. "정말로 반드시 이런 방식으로 해야 하는 일인가?
꼭 해야만 하는 일이긴 한 건가?"

56. 준비가 되었을 때 시작하라.
여러분은 살아오면서 경험을 쌓아왔다. 자꾸 거슬리는 의혹을 무시하지 말라.

57. 어떤 일들은 설명하기보다 실제로 하는 것이 더 쉽다.
명세의 나선에 빠지지 말라. 언젠가는 코딩을 시작해야 한다.

58. 형식적 방법의 노예가 되지 마라.
여러분의 개발 실천방법과 개발 능력의 맥락 안에 넣어보지 않고,
맹목적으로 어떤 기법을 채택하지 말라.

59. 비싼 도구가 더 좋은 설계를 낳지는 않는다.
벤더들의 과장, 어떤 분야의 도그마 그리고 가격표의 휘광에 넘어가지 말라.
도구 자체의 장점만 갖고 판단하라.

60. 팀을 기능 중심으로 조직하라.
설계자와 코더를, 테스트 담당자와 데이터 모델 담당자를 분리시키자 말라.
코드를 만드는 방식에 맞춰 팀을 만들어라.

61. 수작업 절차를 사용하지 말라.
셸 스크립트나 배치 파일은 똑같은 명령을, 똑같은 순서로,
어느 때라도 반복해서 실행 해준다.

62. 일찍 테스트하고, 자주 테스트하라. 자동으로 테스트하라.
매번 빌드할 때마다 실행되는 테스트가 책꽂이의 테스트 계획보다 훨씬 효과적이다.

63. 모든 테스트가 통과하기 전엔 코딩이 다 된게 아니다.
뭐 더 할 말 있나?

64. 파괴자를 써서 테스트를 테스트하라.
코드의 별도 복사본을 만들고,
그 복사본에 고의로 버그를 넣은 다음 테스트가 잡아내는지 검증하라.

65. 코드 커버리지보다 상태 커버리지를 테스트하라.
중요한 프로그램 상태들을 파악해서 테스트하라.
단지 많은 코드 줄 수를 테스트 범위 안에 넣는 것만으로는 충분하지 않다.

66. 버그는 한 번만 잡아라.
인간 테스터가 버그를 찾아내면,
그 때가 인간 테스터가 그 버그를 찾는 마지막 순간이 되어야 한다.
그 순간 이후부터는 자동화된 테스트가 그 버그를 담당하도록 만들라.

67. 한국어도 하나의 프로그래밍 언어인 것처럼 다루라.
코드를 작성하는 것처럼 문서도 작성하라.
DRY원칙을 존중하고, 메타데이터를 사용하고,
MVC 모델을 쓰고, 자동 생성을 이용하고 등등.

68. 문서가 애초부터 전체의 일부가 되게 하고, 나중에 집어 넣으려고 하지 말라.
코드와 떨어져서 만든 문서가 정확하거나 최신 정보를 반영하기는 더 힘들다.

69. 사용자의 기대를 부드럽게 넘어서라.
사용자들이 무엇을 기대하는지 이해한 다음, 그것보다 약간 더 좋은 것을 제공하라.

70. 자산의 작품에 서명하라.
옛날 장인들은 자신의 작업 결과물에 서명하는 일을 자랑스럽게 여겼다.
여러분도 마찬가지여야 한다.

2014년 1월 9일 목요일

False Sharing - 거짓 공유

거짓 공유를 설명하기 전에 필요한 

캐싱과 지역성에 대해 먼저 설명 하겠습니다

캐싱의 기본은 지역성에 근거하는데 

지역성(Locality)은 아래의 추정에 근거합니다
1. 지금 읽힌 데이터는 이후에도 자주 사용될 가능성이 높다.
2. 지금 읽힌 데이터와 인접한 데이터는 이어서 사용될 가능성이 높다.

멀티 코어 CPU는 데이터를 읽어올 때, 캐시 라인 (cache line)이란 단위로 읽어옵니다. 
캐시 라인이라 함은 지역성에 근거해 인접한 데이터를 미리 읽어옴으로써 속도향상을 노리는 것이지요.

하지만 이는 장점이자 독이 되기도 합니다.


이제 본론으로 들어가면

False Sharing 이란 멀티코어 환경에서 각각의 코어에서 접근하고 있는 데이터가 같은 cache line에 있어서 실제로 공유하는 데이터가 아님에도 하드웨어(프로세서)에서는 이를 공유하는 것으로 착각하여 cache coherence 트래픽이 발생하는 것을 의미한다.




그림을 보면, 2개의 스레드가 서로 다른 데이터를 접근하는데 이 데이터가 같은 Cache line에 들어있게 되며 
실제로 인접메모리일 뿐 동시 접근이 일어나지 않는 코드라고 하더라도, 
해당 코드가 어떻게 작성되었는지는 중요치 않습니다. 
캐시 라인은 인접 메모리 접근만으로도 성능 손해를 보면서라도 
데이터의 유효성을 높이고자 하는 판단을 내릴 수 밖에 없습니다.
심각한 경우 성능 하락의 원인이 되기도 합니다.


해결하기 위해서는 간단한 방법으로 data structure 에 적절한 padding(dummy) 을 삽입하여서 막는 방법이 있다. 좀더 나은 방법으로는 data structure 를 각 스레드에 맞도록 privatization 하는 방법이 있다.


결국  메모리를 손해보더라도 속도에서 이득을 보라는 얘기죠.

2013년 11월 11일 월요일

C++ [Windows] 실행 파일이 위치한 경로.. 얻는 방법..

가장 쉽게 이용하는 방법은
GetCurrentDirectory 함수를 사용하면 된다.
하지만 GetCurrentDirectory 의 경우
윈도우 서비스로 어플리케이션을 실행시...
C:\windows\system32\
폴더로 지정되게 된다..

다소 귀찮더라도
아래 코드처럼 하면 어디서 실행되더라도 모듈이 위치한 경로를 정확하게 
얻을 수 있다..

HMODULE hModule = GetModuleHandleW(NULL);
WCHAR path[MAX_PATH];
GetModuleFileNameW(hModule, path, MAX_PATH);
PathRemoveFileSpec(dest);