2015년 2월 23일 월요일

TMAP 4.4.5 APK 티맵 설치 파일

티맵 설치용 APK 4.4.5


원형 매입 LED 분리 방법

최근 아파트의 천정 보조등은 LED인 경우가 많다.
원형으로 매입 형태가 대부분이다.

LED등에 문제가 생겨 교체를 해야 할 경우 다음의 방법으로 탈거하면 된다.


























































실제 원형 매입 LED를 보도록 하자.















천정에서 조심스럽게 분리하면 LED등과 컨버터가 같이 딸려 나온다.



















분리된 매입 LED등의 모습이다. 실제 사진을 보면 이해가 빠르게 된다.
















옆면을 보면 양쪽 옆에 스프링이 대각선으로 위치한 모습이 보인다.

2015년 2월 13일 금요일

삼재(三災)란 무엇인가?

■ 삼재(三災)란?

삼재(三災)는인간에게 9년 주기로 돌아온다는 3가지 재난을 뜻하며 3가지 재난의 종류는대삼재(大三災)라 하여 ① 불의 재난(火災), ② 바람의 재난(風災), ③ 물의 재난(水災)을 말하기도 하지만옛날에는 ① 도병재(刀兵災):연장이나 무기로 입는 재난, ② 역려재(疫癘災):전염병에 걸리는 재난, ③ 기근재(飢饉災):굶주리는 재난으로 해석하기도 했으며요즘에는① 천살(天殺):천재지변으로 당하는 사고나 불가학력적인 사고를 의미, ② 지살(地殺):교통사고나 각종노상의 횡액, ③ 인살(人殺):각종보증이나 사기수에 고통 당함을 의미하는 것으로해석하기도 합니다.
9년 주기로 들어온 이 삼재는 3년 동안 머무르게 되는데 그 첫째 해가 들삼재, 둘째 해가 묵삼재(또는 눌삼재), 셋째 해가 날삼재가 되어 그 재난의 정도가 점점 희박해진다고 한다. 그래서 첫번째 해인 들삼재를 매우 겁내고 조심하는 풍습이 있다.(사람에 따라 셋째 해인 날삼재를 가장불길하다고 믿기도 합니다)

■ 삼재(三災)의 대책

첫째가 매사를 조심하는 방법이요, 두 번째는 부적(符籍)이나 양법(良法)을 행하여 예방하는 방법을 썼다.

① 부적:삼재적을 만들어 몸에 지니고 다니거나 출입문의 위쪽에 붙여 둔다. 부적은 머리가 셋, 발이 하나인 매(三頭一足鷹)를 붉은 물감으로 그린 그림인데 이때 물감은 한약재인 경면주사(鏡面朱砂)를 쓰는 것이 원칙이다.
② 양법:삼재가 들 사람의 옷을 태워서 그 재를 삼거리에 묻거나 그해 첫번째 인일(寅日)이나 오일(午日)에 세 그릇 밥과 3색 과일을 차리고 빈다. 또 종이로 만든 버선본을 대나무에 끼워 정월 대보름에 집의 용마루에 꽂고 동쪽을 향하여 일곱 번 절하고 축원한다.

■ 삼재(三災) 해당년

사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자:해(亥:돼지), 자(子:쥐), 축(丑:소)년이 삼재
신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자:인(寅:범), 묘(卯:토끼), 진(辰:용)년이 삼재
해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자:사(巳:뱀), 오(午:말), 미(未:양)년이 삼재
인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자:신(申:원숭이), 유(酉:닭), 술(戌:개)년이 삼재

예) 2009년은 기축년(己丑年) 소띠의 해이므로 뱀띠, 닭띠, 소띠가 삼재이며 삼재가 머무르는 3년 중 마지막 년인 날삼재에 들어간다.

■ 각 년도 별 해당하는 띠와 삼재

1950년:경인년(庚寅年) 호랑이띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 첫째 해(들삼재)
1951년:신묘년(辛卯年) 토끼띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1952년:임진년(壬辰年) 용띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 셋째 해(날삼재)
1953년:계사년(癸巳年) 뱀띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 첫째 해(들삼재)
1954년:갑오년(甲午年) 말띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1955년:을미년(乙未年) 양띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 셋째 해(날삼재)
1956년:병신년(丙申年) 원숭이띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 첫째 해(들삼재)
1957년:정유년(丁酉年) 닭띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1958년:무술년(戊戌年) 개띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 셋째 해(날삼재)
1959년:기해년(己亥年) 돼지띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 첫째 해(들삼재)
1960년:경자년(庚子年) 쥐띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1961년:신축년(辛丑年) 소띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 셋째 해(날삼재)
1962년:임인년(壬寅年) 호랑이띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 첫째 해(들삼재)
1963년:계묘년(癸卯年) 토끼띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1964년:갑진년(甲辰年) 용띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 셋째 해(날삼재)
1965년:을사년(乙巳年) 뱀띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 첫째 해(들삼재)
1966년:병오년(丙午年) 말띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1967년:정미년(丁未年) 양띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 셋째 해(날삼재)
1968년:무신년(戊申年) 원숭이띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 첫째 해(들삼재)
1969년:기유년(己酉年) 닭띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1970년:경술년(庚戌年) 개띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 셋째 해(날삼재)
1971년:신해년(辛亥年) 돼지띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 첫째 해(들삼재)
1972년:임자년(壬子年) 쥐띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1973년:계축년(癸丑年) 소띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 셋째 해(날삼재)
1974년:갑인년(甲寅年) 호랑이띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 첫째 해(들삼재)
1975년:을묘년(乙卯年) 토끼띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1976년:병진년(丙辰年) 용띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 셋째 해(날삼재)
1977년:정사년(丁巳年) 뱀띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 첫째 해(들삼재)
1978년:무오년(戊午年) 말띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1979년:기미년(己未年) 양띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 셋째 해(날삼재)
1980년:경신년(庚申年) 원숭이띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 첫째 해(들삼재)
1981년:신유년(辛酉年) 닭띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1982년:임술년(壬戌년) 개띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 셋째 해(날삼재)
1983년:계해년(癸亥年) 돼지띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 첫째 해(들삼재)
1984년:갑자년(甲子年) 쥐띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1985년:을축년(乙丑年) 소띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 셋째 해(날삼재)
1986년:병인년(丙寅年) 호랑이띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 첫째 해(들삼재)
1987년:정묘년(丁卯年) 토끼띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1988년:무진년(戊辰年) 용띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 셋째 해(날삼재)
1989년:기사년(己巳年) 뱀띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 첫째 해(들삼재)
1990년:경오년(庚午年) 말띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1991년:신미년(辛未年) 양띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 셋째 해(날삼재)
1992년:임신년(壬申年) 원숭이띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 첫째 해(들삼재)
1993년:계유년(癸酉年) 닭띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1994년:갑술년(甲戌年) 개띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 셋째 해(날삼재)
1995년:을해년(乙亥年) 돼지띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 첫째 해(들삼재)
1996년:병자년(丙子年) 쥐띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 둘째 해(묵삼재)
1997년:정축년(丁丑年) 소띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 셋째 해(날삼재)
1998년:무인년(戊寅年) 호랑이띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 첫째 해(들삼재)
1999년:기묘년(己卯年) 토끼띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2000년:경진년(庚辰年) 용띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 셋째 해(날삼재)
2001년:신사년(辛巳年) 뱀띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 첫째 해(들삼재)
2002년:임오년(壬午年) 말띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2003년:계미년(癸未年) 양띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 셋째 해(날삼재)
2004년:갑신년(甲申年) 원숭이띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 첫째 해(들삼재)
2005년:을유년(乙酉年) 닭띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2006년:병술년(丙戌年) 개띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 셋째 해(날삼재)
2007년:정해년(丁亥年) 돼지띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 첫째 해(들삼재)
2008년:무자년(戊子年) 쥐띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2009년:기축년(己丑年) 소띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 셋째 해(날삼재)
2010년:경인년(庚寅年) 호랑이띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 첫째 해(들삼재)
2011년:신묘년(辛卯年) 토끼띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2012년:임진년(壬辰年) 용띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 셋째 해(날삼재)
2013년:계사년(癸巳年) 뱀띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 첫째 해(들삼재)
2014년:갑오년(甲午年) 말띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2015년:을미년(乙未年) 양띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 셋째 해(날삼재)
2016년:병신년(丙申年) 원숭이띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 첫째 해(들삼재)
2017년:정유년(丁酉年) 닭띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2018년:무술년(戊戌年) 개띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 셋째 해(날삼재)
2019년:기해년(己亥年) 돼지띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 첫째 해(들삼재)
2020년:경자년(庚子年) 쥐띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2021년:신축년(辛丑年) 소띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 셋째 해(날삼재)
2022년:임인년(壬寅年) 호랑이띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 첫째 해(들삼재)
2023년:계묘년(癸卯年) 토끼띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2024년:갑진년(甲辰年) 용띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 셋째 해(날삼재)
2025년:을사년(乙巳年) 뱀띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 첫째 해(들삼재)
2026년:병오년(丙午年) 말띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2027년:정미년(丁未年) 양띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 셋째 해(날삼재)
2028년:무신년(戊申年) 원숭이띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 첫째 해(들삼재)
2029년:기유년(己酉年) 닭띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2030년:경술년(庚戌年) 개띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 셋째 해(날삼재)
2031년:신해년(辛亥年) 돼지띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 첫째 해(들삼재)
2032년:임자년(壬子年) 쥐띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2033년:계축년(癸丑年) 소띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 셋째 해(날삼재)
2034년:갑인년(甲寅年) 호랑이띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 첫째 해(들삼재)
2035년:을묘년(乙卯年) 토끼띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2036년:병진년(丙辰年) 용띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 셋째 해(날삼재)
2037년:정사년(丁巳年) 뱀띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 첫째 해(들삼재)
2038년:무오년(戊午年) 말띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2039년:기미년(己未年) 양띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 셋째 해(날삼재)
2040년:경신년(庚申年) 원숭이띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 첫째 해(들삼재)
2041년:신유년(辛酉年) 닭띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2042년:임술년(壬戌年) 개띠의 해 - 인(寅:범띠), 오(午:말띠), 술(戌:개띠) 출생자 삼재(三災) 셋째 해(날삼재)
2043년:계해년(癸亥年) 돼지띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 첫째 해(들삼재)
2044년:갑자년(甲子年) 쥐띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2045년:을축년(乙丑年) 소띠의 해 - 사(巳:뱀띠), 유(酉:닭띠), 축(丑:소띠) 출생자 삼재(三災) 셋째 해(날삼재)
2046년:병인년(丙寅年) 호랑이띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 첫째 해(들삼재)
2047년:정묘년(丁卯年) 토끼띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 둘째 해(묵삼재)
2048년:무진년(戊辰年) 용띠의 해 - 신(申:원숭이띠), 자(子:쥐띠), 진(辰:용띠) 출생자 삼재(三災) 셋째 해(날삼재)
2049년:기사년(己巳年) 뱀띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 첫째 해(들삼재)
2050년:경오년(庚午年) 말띠의 해 - 해(亥:돼지띠), 묘(卯:토끼띠), 미(未:양띠) 출생자 삼재(三災) 둘째 해(묵삼재)

■ 60갑자 순서

01. 甲子(갑자)
02. 乙丑(을축)
03. 丙寅(병인)
04. 丁卯(정묘)
05. 戊辰(무진)
06. 己巳(기사)
07. 庚午(경오)
08. 辛未(신미)
09. 壬申(임신)
10. 癸酉(계유)
11. 甲戌(갑술)
12. 乙亥(을해)
13. 丙子(병자)
14. 丁丑(정축)
15. 戊寅(무인)
16. 己卯(기묘)
17. 庚辰(경진)
18. 辛巳(신사)
19. 壬午(임오)
20. 癸未(계미)
21. 甲申(갑신)
22. 乙酉(을유)
23. 丙戌(병술)
24. 丁亥(정해)
25. 戊子(무자)
26. 己丑(기축)
27. 庚寅(경인)
28. 辛卯(신묘)
29. 壬辰(임진)
30. 癸巳(계사)
31. 甲午(갑오)
32. 乙未(을미)
33. 丙申(병신)
34. 丁酉(정유)
35. 戊戌(무술)
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. 癸亥(계해)

■ 십간(十干)의 의미

갑(甲):갑(甲)은 만물이 부갑( 甲)을 터뜨리고 나오는 것'이고, 부(符)는 부(孚)로 발음이 같으므로 달걀의 껍질인 것이다. 만물이 발생해 오는 열매의 껍질을 쓰고 있는 상태를 「처음」으로 생각해서 맨 처음에 내놓은 것이다.

을(乙):만둘이 생기어 알력이는 것을 말한다고 있다. 알력인다는 것은 싹이 트기 시작하여 아직 굴곡해서 펴지 못하고 얽히어 있는 모양을 형용하고 있다, 그 글자 자F체에 구부러진 모양이 보인다.

병(丙):양(陽)의 길이 현저하게 밝은 것을 말한다고 되어 있다 「석명(釋名)」이라는 책에 따르면 병(丙)은 병(炳)이어서, 만물이 생기어 밝고 확실해 지는 것이고, 싹트기 시작한 싹이 잠깐 보기에도 그렇다고 인정될 상태에 이르렀다는 것이다.

정(丁):만물의 정장(丁壯)한 것을 말한다고 있고, 사람인 20·30세경을 정장이라 하는 것처럼 싹이 자라서 이미 튼튼하게 된 것을 나타낸다.

무(戊):무(戊)와 같아서 모두 무성한 것으로, 싹이 생장해서 더욱 무성해 가는 것을 나타낸다.

기(己):기(紀)와 같으므로, 모두 정해진 형상으로 되고, 정연히 보아 분별할 수 있는 상태를 표시한다.

경(庚):경(更)과 같이 물건을 단단히 뭉친다는 의미를 가지며, 음기가 만물을 뭉치는 것을 말한다고 하고, 지금까지 새싹, 무성한 잎으로 신장(伸張)한 것이 기후가 가을로 향하고, 비나 바람이나 흐림 등의 냉기로 죄어 경화(硬化)하는 상태를 표시한다.

신(辛):신(新)과 같으므로, 물건이 물건으로서 처음으로 새롭게 된다는 것은, 모두 그 속이 차고 성숙해 오는 것을 표시한다. '맵다'라는 맛에 부회(附會)한 것이다.

임(壬):임(任)과 같으므로, 임(姙)으로도 통하며 하물(荷物)을 짊어지는 것이다. 양기(陽氣)가 작동하여 만물을 밑에 임양(任養)하는 것을 말한다 하며, 임양한다는 것은 짊어지고 기른다는 것으로, 여름이 지나면 열매가 맺고, 다음의 맹아(萌芽)를 갖는데 이르는 상태를 상징하는 말이다.

계(癸):규(揆)와 같으므로, 계산하는 것 즉 내부에 잉태하여 안고 있는 맹아의 형상이 갖추어져 약간 그 길이를 헤아릴 정도가 되었다는 것을 표시하는 것으로 만물을 규탁(規度)할 수 있는 것을 말한다. 

2015년 2월 12일 목요일

세교 삼미마을 엘크루 19단지 아파트 분양정보

홈페이지 : http://cafe.naver.com/sekyo19
신주소 : 경기도 오산시 오산대역로 232
구주소 : 경기도 오산시 수청동 625
시행사 : 한국주택공사
시공사 : 대우조선해양건설
면적 : 74~84㎡
단지정보 : 498세대 / 7개동 / 22층 / 지역난방 / 열병합
교육환경 : 세미초, 매홀중, 매홀고
교통환경 : 1번국도, 전철1호선 오산대역, 경부선 오산역, KTX 신평택역
편의시설 : 홈플러스, 물향기수목원, 필봉산
입주시기 : 2013년 11월 29일
















C# Interop - C#과 C API의 상호운영

C#은 매우 강력한 각종 기능과 Class를 제공하지만, Windows Application의 작성을 위해서는 C로 작성된 Library를 사용하여야 하는 경우가 많이 발생된다. C#은 기본적으로 C의 Pointer를 지원하지 않고, Managed Code의 메모리 관리 체계는 근본적으로 C(Unmanaged Code)와 차이가 많기 때문에 C와의 호환을 위해서는 특수한 기법을 사용하여야 가능하다. C#은 이를 위하여 PInvoke와 Marshaling 등의 기능을 제공한다.

1. Using C DLL (PInvoke : Plaform Invocation Service)
C#은 C DLL의 Unmanaged Function을 호출할 수 있도록 플랫폼 호출 서비스 (PInvoke)를 제공한다. 이는 일반적인 C로 작성된 DLL이나 Win32 API를 호출하는 용도로 사용된다.

1.1 DLL 함수의 정의
PInvoke를 이용하여 Win32 API를 정의하는 방법은 “DllImport” 속성을 사용한다. DllImport 속성은 “DllImportAttribute” Class를 사용하는데, 이 Class의 생성자는 아래와 같다.
public DllImportAttribute(string dllName)
즉, 사용하고자 하는 DLL의 파일명을 파라미터로 가지므로, DllImport 속성은 DLL의 파일명을 정의하고, 실제 사용하고자 하는 함수는 속성 하단의 함수선언에 의하여 정의된다.

[user32.dll의 MessageBox 함수의 정의]
using System.Runtime.InteropServices

[DllImport(“user32”)]
public static extern int MessageBox(int hWnd, String pText, String pCaption, int uType);
위와 같이 선언하면 C# Code내에서 “MessageBox”라는 이름으로 함수를 호출할 수 있다. 함수는 반드시 “static extern”으로 선언하여 사용하도록 한다.

1.2 DllImport 옵션

위에서 사용된 DllImport Attribute는 몇가지 옵션필드를 가질 수 있다. 이 필드 중 주요한 항목은 아래와 같다. 자세한 내용은 DllImportAttribute Class를 참조한다.

필드
설명
Calling Convention
DLL 내의 Export 함수에 대한 Calling Convention을 지정할 수 있다.
Cdecl, Winapi, StdCall 등을 포함하는 CallingConvention Enumerator를 지원하며, 기본값은 StdCall 이다.
CharSet
문자열에 사용할 Character Set을 설정한다.
None(자동), Unicode 값을 가질 수 있다.
Entry Point
DLL 내의 함수가 호출되는 이름을 나타낸다.
이를 이용하면 함수진입점을 지정하여, 선언시 다른 이름으로 별칭을 이용할 수도 있다.

Calling Convention
DLL은 VC++에서 제작시 Calling Convention을 지정할 수 있는데, 이 Calling Convention을 제작시 정의된 것과 일치시켜야 함수가 정상적으로 호출된다. Calling Convention 옵션은 DLL 내의 Export 함수에 대한 Calling Convention을 지정하는 옵션이며, 이는 Cdecl, Winapi, StdCall 등을 포함하는 CallingConvention Enumerator를 지원하며, 기본값은 StdCall 이다. 대부분의 DLL 함수는 StdCall 방식으로 제작되므로, 대부분 생략가능하다.
// Cdecl 방식의 함수 선언
[DllImport("msvcrt.dll", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl)]
public static extern int printf(String format, int i, double d); 

// StdCall 방식의 함수 선언
[DllImport("msvcrt.dll", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
public static extern int printf(String format, int i, String s);
CharSet
DLL 함수에서 사용되는 문자열에 사용할 Character Set을 설정한다. 이 역시 DLL 제작시 사용된 Character Set에 일치시켜야 한다. 이 속성은 CharSet Enumerator를 사용하며 None(자동), Unicode, Ansi 등의 값을 가질 수 있다.
// Unicode를 사용하도록 설정
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);

EntryPoint
DLL 내의 함수가 호출되는 이름을 나타낸다. 정의한 함수명과 실제 DLL의 함수명이 일치하면 생략가능하지만, 만약 다른 이름으로 함수를 정의하고 싶다면, 이 옵션을 사용한다.
아래는 DllImport Attribute를 사용하여 함수에 별칭을 부여한 예이다.
[DllImport(“user32”, CharSet = CharSet.UniCode, EntryPoint = “MessageBoxW”)]
public static extern int MsgBox(int hWnd, String pText, String pCaption, int uType);

1.3 Data Type의 변환
DLL함수의 정의 시, 가장 많이 접하게 되는 문제는 C로 표현된 각 데이터 타입을 C#에서 어떻게 정의할것인가에 대한 문제이다. Unmanaged Code의 Data Type에 대한 C#(Managed Code)에서 정의는 아래의 표와 같이 1 대 1로 매핑이 되므로 아래 표를 참조하여 그대로 정의하면 된다.

C (Unmanaged Code)
C# (Managed Code)
HANDLE, void* 또는 일반 pointer
IntPtr
BYTE, unsigned char
Byte
short
Short
WORD, unsigned short
Ushort
int
int
UINT, unsigned int
uint
long
int
BOOL, long
int
DWORD, unsigned long
uint
char
char
LPSTR, char*
string 또는 StringBuilder
LPCSTR, const char*
string 또는 StringBuilder
BSTR
string
float
float
double
double
HRESULT
int
VARIANT
object

String Type의 변환
Unmanaged Code를 사용하는 경우, char*는 상황에 따라 다르게 표현되며, String 또는 StringBuilder를 사용할 수 있다. 각 상황에 따른 String의 처리는 아래와 같다.
1. Call by value
String을 Value에 의하여 전달하는 경우는 string Type으로 사용한다. 즉, 단순히 String을 DLL함수로 전달하는 경우는 string으로 정의하면 된다.
C
int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
C#
[DllImport(“user32”)]
public static extern int MessageBox(int hWnd, String pText, String pCaption, int uType);

2. Call by Reference(Pointer)
Parameter를 Pointer로 In/Out으로 사용할 경우에는 StringBuilder를 사용한다. 즉, DLL함수로부터 String값을 전달받는 경우, StringBuilder를 사용한다.
C
UINT GetSystemDirectory(LPTSTR lpBuffer, UINT uSize);
C#
[DllImport( "Kernel32.dll)]
public static extern int GetSystemDirectory(StringBuilder sysDirBuffer, int size);

String Type 또는 Call By Reference 방식을 사용하는 경우, 주의를 기울여야 한다. 통상, DLL내부에서 생성한 메모리를 리턴받아서 .NET에서 사용하게 되는 경우, 시스템이 죽는 현상이 발생할 수 있다. 즉, 아래와 같이 char*를 DLL 내부에서 생성하고, .NET에서 메모리를 리턴받아 참조하는 경우, 프로그램이 비정상적으로 종료될 수 있다.
C
char* GetLastError();
C#
[DllImport("somedll.dll"]
public static extern string GetLastError();
string s = GetLastError();

이와 같은 현상이 발생되는 경우, DLL 함수 자체를 변경하거나, 함수를 사용하지 않는 쪽으로 검토하여야 한다. 위의 코드에서는 DLL을 Call By Reference로 수정하면 문제가 해결된다.
C
int GetLastError(char* sError);
C#
[DllImport("somedll.dll"]
public static extern int GetLastError(StringBuilder error);
StringBuilder sb = new StringBuilder();
GetLastError(sb);

2. Marshalling
앞에서 일반적인 데이터형을 사용하는 DLL 함수의 사용법을 배웠다. 하지만 C로 제작된 DLL의 대다수는 아래와 같이 struct 형의 파라미터를 사용하는 경우가 많다. 이러한 경우 어떻게 C#에서 함수를 정의하여야 할까?
Struct MyStruct
{
   int n;
   char* s;
}

void SomeFn(MyStruct st);
2.1 StructLayoutAttribute
StructLayout 속성은 StructLayoutAttribute Class를 사용한다. 이 StructLayout은 생성자에서 LayoutKind Type을 파라미터로 받는다. 즉, StructLayout 하단에 정의된 struct가 메모리상에 어떻게 저장되는지를 설정하여야 한다. LayoutKind형은 Sequential, Explicit, Auto의 값을 가지는데, 대부분의 경우 Sequential 한 Struct를 위하여 이 속성을 사용하므로 항상 “LayoutKind.Sequential”을 사용하면 된다.
[C]
struct MyStruct
{
   int n;
   char* s;
}

void SomeFn(MyStruct st);
[C#]
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct MyStruct
{
   int n;
   string s;
}

[DllImport("somedll.dll"]
public static extern void SomeFn(MyStruct st);

Pack 옵션
VC++에서 DLL을 제작할 때, Byte Align을 설정할 수 있다. 이는 구조체가 연속된 메모리에 저장될 때, 성능향상을 위하여 몇바이트를 기준으로 정렬되느냐에 대한 설정인다. 이는 DLL 사용시, DLL이 어떤 설정으로 되어 있는지를 알면 그에 따라 설정하면 된다. 만약 DLL이 시스템의 디폴트값을 사용하고 있다면, 생략하면 된다.
[StructLayout(LayoutKind.Sequential, Pack=8)]
public struct MyStruct
{
   int n;
   string s;
}
Struct 내에서의 문자열 배열
Struct 내에서 고정된 길이의 문자배열을 사용하기 위해서는 “MarshalAs” Attribute를 사용하여 Data의 Type과 길이를 지정하여야 한다.
[C]
Struct tpstart_t
{
   char usrname[18];
   char cltname[18];
   char dompwd[18];
   char usrpwd[18];
   int flags;
}
[C#]
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct tpstart_t
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=18)] public string usrname;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=18)] public string cltname;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=18)] public string dompwd;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=18)] public string usrpwd;
    public int flags;
}

2.2 Array Marshaling
함수에 배열을 Parameter로 사용하기 위해서 “In/Out” Attributes 또는 ref를 사용한다.
[C]
int TestArrayOfInts(int* pArray, int pSize);

int TestRefArrayOfInts(int** ppArray, int* pSize);

int TestMatrixOfInts(int pMatrix[][COL_DIM], int row);

int TestArrayOfStrings(char** ppStrArray, int size);

int TestArrayOfStructs(MYPOINT* pPointArray, int size);

int TestArrayOfStructs2 (MYPERSON* pPersonArray, int size);
[C#]
[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern int TestArrayOfInts([In, Out] int[] array, int size );

[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern int TestRefArrayOfInts( ref IntPtr array, ref int size );

[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern int TestMatrixOfInts([In, Out] int[,] pMatrix, int row );   

[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern int TestArrayOfStrings( [In, Out] String[] stringArray, int size );

[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern int TestArrayOfStructs([In, Out] MyPoint[] pointArray, int size ); 

[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern int TestArrayOfStructs2( [In, Out] MyPerson[] personArray, int size );

3. Using Pointer
C와 C#의 가장 큰 차이점 중 하나는 Pointer의 존재여부이다. Pointer는 C에서 워낙 광범위하게 사용되고 있으므로, C#에서 C 함수를 사용하기 위해서는 Pointer의 처리가 필수적이다.
.NET에서는 이러한 C언어와의 상호운영을 위하여 Marshal Class를 제공하는데, Marshal Class는 관리되지 않는 메모리를 할당하고, 관리되지 않는 메모리 블록을 복사하고, 관리되는 형식을 관리되지 않는 형식으로 변환하는 메서드의 컬렉션 및 관리되지 않는 코드와 상호 작용할 때 사용되는 기타 메서드의 컬렉션을 제공한다.
즉, Managed Code의 메모리와 Unmanaged Code의 메모리를 상호 변환 또는 관리하기 위한 일련의 Method를 제공하므로, DLL 함수내에서 만나게되는 각종 Pointer관련 파라미터의 처리에 활용한다.

IntPtr & Marshal Class
.NET에서 C의 Pointer를 표현하기 위한 데이터타입이다. Pointer라는 것은 실제로 주소값이므로, 시스템에 따라 32bit 또는 64bit 정수형으로 표기되는데, 이러한 Pointer형을 지원하기 위한 데이터타입이다. C 함수는 그 특성상, 메모리를 할당하기 위한 alloc 계열의 함수와 할당된 메모리의 Pointer를 파라미터로 받는 함수가 다수 존재한다. 이러한 메모리 주소 위주의 함수들을 .NET에서 사용하는 경우, 거의 필수적으로 IntPtr이 사용되며, 이는 Marshal Class와 함께 주로 사용된다.

아래의 예는 국내 미들웨어인 TMAX를 C#에서 사용한 예인데, 이와 같이 C-DLL에서 메모리를 할당(관리되지 않는 메모리)하고 이 메모리에 특정 Struct를 복사하는 구조로 작성되는 경우, 일반적인 C#의 함수로는 구현이 불가능하다. 따라서 이와 같은 C의 Unmanaged Memory에 대한 각종 처리를 담당하는 역할을 수행한다.
// 접속을 위한 메모리 할당 : DLL 함수 호출 
int nAddr = TMaxLib.tpalloc("TPSTART", "", 0);

// C Style 메모리주소를 IntPtr로 변환
IntPtr pMem = new IntPtr(nAddr);

// TMax 접속을 위한 start_t struct 생성 : StructLayout으로 정의됨
TMaxLib.tpstart_t tpinfop;
tpinfop.cltname = ClientName + '\0';
tpinfop.usrname = UserName + '\0';
tpinfop.dompwd = "\0";
tpinfop.usrpwd = "\0";
tpinfop.flags = TMaxLib.TPU_DIP;

// 마샬링을 이용하여 start_t 구조체를 할당한 Buffer로 복사
Marshal.StructureToPtr(tpinfop, pMem, true);

// T-Max 접속
if(TMaxLib.tpstart(pMem.ToInt32()) == -1)
{
   m_sLastError = "연결에 실패하였습니다.";
   return false;
}

// Buffer 메모리 해제
TMaxLib.tpfree(nAddr);

Marshal Class Methods
Marshal Class는 Pointer 관련 처리를 위하여 매우 자주 사용하게 되는데, 자주 사용하게 되는 함수는 아래와 같다.
AllocHGlobal
Unmanaged Memory 영역에 특정 바이트 만큼의 메모리를 할당한다.
함수에 할당된 메모리주소를 파라미터로 넘겨야 하는 경우 사용할 수 있다.
FreeHGlobal
AllocHGlobal로 할당된 메모리를 해제한다.
AllocHGlobal은 Unmanaged Memory를 할당하므로 C와 마찬가지로 직접 메모리를 Delete해야 한다.
Copy
Managed Type에서 Unmanaged type의 Pointer로 데이터를 복사한다.
ReadByte
Unmanaged Memory로부터 데이터를 바이트 단위로 Read한다.
WriteByte
Unmanaged Memory에 데이터를 바이트 단위로 Write한다.
SizeOf
Unmanaged Type의 크기를 리턴한다.
PtrToStructure
Unmanaged Type의 Memory Pointer로부터 Managed Object에 복사한다.
StructureToPtr
Managed Type의 오브젝트를 Unmanaged Memory의 Pointer에 복사한다.

Function Pointer
C는 Callback Function 등과 같이 함수 자체의 Pointer를 파라미터로 많이 사용한다. 이 Function Pointer를 C#에서 정의하기 위해서는 Delegate를 선언하여 처리한다. 이에 대한 Marshaling 방법은 아래와 같다.
[C]
void TestCallBack(FPTR pf, int value);
void TestCallBack2(FPTR2 pf2, char* value);
[C#]
public delegate bool FPtr( int value );
public delegate bool FPtr2( String value );

[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern void TestCallBack( FPtr cb, int value );   

[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern void TestCallBack2( FPtr2 cb2, String value ); 
...
public class App
{
   public static void Main()
   {
      FPtr cb = new FPtr( App.DoSomething );
      LibWrap.TestCallBack( cb, 99 );
      FPtr2 cb2 = new FPtr2( App.DoSomething2 );
      LibWrap.TestCallBack2( cb2, "abc" );
   }

   public static bool DoSomething( int value )
   {
      Console.WriteLine( "\nCallback called with param: {0}", value );
}
   public static bool DoSomething2( String value )
   {
      Console.WriteLine( "\nCallback called with param: {0}", value );
   }
}
Void Pointer
void pointer는 기본적으로 UnmanagedType.AsAny Type의 object 형식으로 변환하며, void*의 type이 미리 예상될 때, 임의의 Data Type으로 Overload 하여 사용할 수 있다.
[C]
void SetData(DataType typ, void* object)
[C#]
[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern void SetData( DataType t, [ MarshalAs( UnmanagedType.AsAny )] Object o );

[ DllImport( "..\\LIB\\PinvokeLib.dll", EntryPoint="SetData" )]
public static extern void SetData2( DataType t, ref double i );
[ DllImport( "..\\LIB\\PinvokeLib.dll", EntryPoint="SetData" )]
public static extern void SetData2( DataType t, String s );
4. Using MFC
본인은 Visual C++을 전문적으로 개발하다가 .NET의 발표와 함께 C#으로 개발하기 시작하였다. C#으로 개발을 하면서 “기존에 만들어두었던 MFC 기반의 많은 Class를 C#에서 그대로 활용할 수 있을까?” 라는 문제와 위에서 설명한 바와 같이 대부분의 C API를 C#에서 사용가능 하지만, 수많은 Pointer 위주의 함수를 일일이 PInvoke/Mashal을 이용하여 변환해서 사용하는 것은 상당한 귀찮은 일이라 “C로 만든 로직을 그대로 .NET에서 사용할 수 있는 방법은 없을까?” 라고 하는 문제에 항상 관심을 가져왔다.
사실 답은 간단한데, “C와 .NET 라이브러리 모두를 사용가능한 언어를 사용”하면 해결이 된다. 즉, C를 이용하여 기존의 C 라이브러리를 그대로 사용하고, .NET을 이용하여 .NET에서 사용가능한 Class를 만들면 되는 것이다.
이러한 능력은 현재 Visual C++을 사용하면 가능하다. 예전에는 Managed C++이라고 불리었고, 현재는 C++/CLI라고 불리는 기능을 사용하면 된다. 물론 Visual C++을 이미 사용할 수 있다면, 쉽게 가능하지만, VC++에 익숙하지 않더라도, 단지 C 라이브러리를 .NET에서 사용가능한 Class를 만드는데 목적을 둔다면 충분히 약간의 학습으로 가능하다.

4.1 C++/CLI
Visual C++은 Windows SDK, MFC와 .Net Framework를 동시에 사용하여 개발가능한 능력을 갖고 있다. C++/CLI(이전 Managed Extensions for C++) 불리우는 .Net Framework를 위한 언어규격을 사용하여 .NET Framework를 위한 코드를 개발할 수 있다.
이를 이용하여 .Net과 C API의 중간자로서, .Net에서 직접적으로 사용하기 힘든 각종 C Library를 .Net에서 직접사용할 수 있도록 하는 DLL을 만들 수 있다. 즉, 내부적으로는 C API/MFC를 사용하고 외부로의 기능노출을 .Net으로 개발하여 중간자 역할을 하는 DLL을 개발가능하다.

특징
- 내부적으로 C API, MFC 등 Visual C++의 모든 기능을 사용할 수 있다.
- C++/CLI를 사용하여 .Net의 모든 Class를 사용할 수 있다.
- C++/CLI를 사용하여 .Net에서 참조만으로 사용가능한 Class를 만들 수 있다.

API Proxy Class
.Net에서 MFC 기능을 사용하고 싶다거나, 복잡한 Pointer 구조 등을 사용하는 C API를 .Net에서 사용하고 싶은 경우, 기존의 Visual C#이나 Visual Basic에서는 사용이 불가하거나, 그 사용법의 복잡함으로 인하여 개발이 용이하지 않은 경우가 많다.
이러한 경우, Visual C++을 이용하여 C Library를 .Net과 호환시켜주는 Proxy Class를 만들어, .Net에서 사용할 수 있도록 할 수 있다.
















이렇게 하는 경우 .Net에서 사용할 수 없는 C++ Class를 사용할 수 있게 하여 C++ 개발자와 C# 개발자의 협력이 가능하다.


4.2 C++/CLI 구문

Class 선언
C++/CLI에서 관리되는 형식의 선언방법은 아래와 같다.
ref class Block {};                // reference class
value class Vector {};             // value class
interface class I {};        // interface class
ref class Shape abstract {};       // abstract class
ref class Shape2D sealed: Shape{}; // derived class

개체 선언
C++/CLI에서 관리되는 형식의 개체선언은 아래와 같이 “^”를 이용하여 선언한다. “^”는 관리되는 개체형식의 Pointer를 의미한다.

public ref class Form1 : System::Windows::Forms::Form {
System::ComponentModel::Container^ components;
System::Windows::Forms::Button^ button1;
   System::Windows::Forms::DataGrid^ myDataGrid;
   System::Data::DataSet^ myDataSet;
};
관리되는 Object 생성
C++/CLI에서 Object의 생성은 “gcnew”를 사용한다.
Button^ button1 = gcnew Button;        // managed heap
int * pi1 = new int;                   // native heap
Int32^ pi2 = gcnew Int32;              // managed heap
CLR 배열
“array” keyword 사용
array<Object^>^ myArr
array<int,3>^ myArr
Property (속성)
“property” keyword 사용
public ref class Vector sealed { 
   double _x;

public:
   property double x 
   {
      double get()             { return _x; }
      void   set( double newx ){ _x = newx; }
   } 
};
4.3 Making C++/CLI DLL
간단한 DLL을 만들기 위하여 아래와 같은 기능을 가지는 Class를 DLL로 만들기로 한다.

- MFC의 CFtpConnection Class를 .NET에서 사용할 수 있는 CLR Class를 제작
- 동작의 시험을 위하여 Connect/Disconnect 기능만을 구현한다.

아래와 같이 새 프로젝트를 선택하고 “Visual C++” 카테고리의 “클래스 라이브러리”를 선택하여 프로젝트를 생성한다.
프로젝트 속성 페이지에서 “구성속성 ? 일반” 카테고리를 선택하여 “MFC사용” 항목에서 “공유 DLL에서 MFC사용”을 선택한다.

MFC를 사용하기 위하여 Stdafx.h에 아래와 같이 MFC Header 파일을 포함시킨다.
[Stdafx.h]
#include <afxwin.h> 
#include <afxinet.h>
.Net에서 사용할 CLR Class를 작성한다. 실제 내부적으로 사용할 MFC의 CFTPConnection Class를 위한 변수를 멤버로 추가한다. Class는 Resource 반환을 위하여 IDisposable Interface를 구현한다. 또한 서버의 접속/접속해제를 위한 함수를 추가한다. 함수의 파라미터는 .NET에서 사용할 것이므로 CLR Type을 사용한다.
[FTPProxySample.h]
namespace FTPProxySample {

    public ref class FtpConnection : public IDisposable
    {
    public:
        FtpConnection();
        ~FtpConnection();

        void Open(String^ serverURL, int Port, String^ ClientName, String^ UserID, String^ Pwd);
        void Close();

    private:
        CInternetSession* m_pSession;
        CFtpConnection*  m_pFtpConn;
    };
}
실제 Connect와 Close의 구현을 추가한다. 각 함수는 실제 MFC Class의 오브젝트를 이용하여 처리를 하면된다. 이렇게 하는 경우, .NET에서 함수를 호출하면, 함수에서 MFC를 접근하여 각 처리를 수행하게 된다.
[FTPProxySample.cpp]
namespace FTPProxySample
{
    FtpConnection::FtpConnection()
    {
        m_pSession = NULL;
        m_pFtpConn = NULL;
    }

    FtpConnection::~FtpConnection()
    {
        Close();
        System::GC::SuppressFinalize(this);
    }

    void FtpConnection::Open(String^ ServerURL, int Port, String^ ClientName, String^ UserID, String^ Pwd)
    {
        CString serverURL(ServerURL);
        CString userID(UserID);
        CString password(Pwd);
        CString clientName(ClientName);

        m_pSession = new CInternetSession(clientName);

        // FTP 접속
        try
        {
            m_pFtpConn = m_pSession->GetFtpConnection(serverURL, userID, password, Port);
        }
        catch(CInternetException* pe)
        {
            // Exception 처리
        }
    }

    void FtpConnection::Close()
    {
        if(m_pSession != NULL)
        {
            m_pSession->Close();
            delete m_pSession;
            m_pSession = NULL;
            m_pFtpConn = NULL;
        }
    }
}
컴파일을 하면, .NET에서 참조가능한 FTPProxySample.dll이 만들어진다.

4.4 Using C++/CLI DLL
만들어진 DLL은 .NET용 DLL이므로, .NET 프로젝트에서 “참조추가”를 하면, 바로 DLL내의 Class를 사용할 수 있다.
아래와 같이 참조한 DLL의 Class의 객체를 생성하여 사용한다.
private void button1_Click(object sender, EventArgs e)
{
    using (var ftp = new FTPProxySample.FtpConnection())
    {
        try
        {
            ftp.Open("server-url", 21, "Test", "id", "password");
            MessageBox.Show("Success");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }            
    }
}