336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

약 7개월 전, 개인적으로 힘든일이 있어 비행기라도 보면 나아질까 찾았던 전쟁기념관.

이번엔 사진을 제대로 찍어보고자 다시 찾아갔다.

형제의 상, 6.25 당시 한국군 형과 북한군 동생이 전장에서 만났다... 

맨 처음 찍었을땐 약간 어두웠지만, P모드로 약간 어두운 곳에서 반셔터 후, 

카메라를 옮겨 촬영. 몇번 시도 하니 괜찮게 나왔다.



B-52 스트라토 포트리스, 하늘이 맑다. 



KT-1 훈련기. 



F-51 무스탕 전투기



6.25 에서 노획된 MIG-19 전투기, 북한 공군 마크가 뚜렷하다.



F-4D Phantom전투기



세종대왕함 전투 지휘실, 배경이 어두워서인지 약간 흐릿하다.



한국전쟁 초기, 연락기로 공중공격 하는 모습


서울 수복 시, 중앙청 앞에 태극기를 계양하는 모습


인천상륙작전 이후, 38선 돌파 모습



중공군 투입 후, 장진호 전투 관련 사진


포로수용소 팻말.



정전협정 이후, 설치된 군사분계선 팻말


 

나오는 길, 전쟁기념관을 바라봤을 때, 왼쪽에는 6.25에 참전한 부대의 깃발들이 나부끼고 있다.


전쟁기념관, 베트남 전쟁 관련 디오라마. 


베트남 전쟁에 참전한 한국군의 '중대 전술기지' 



김일성이 사용했던 자동차, 한국전쟁때 노획 했다고 한다.




이승만 초대 대통령 의전용 차량



자취방에 도착해서 사진을 하나씩 살펴 보는데... 뭐 맘에 들게 나온 사진이 하나도 없다. 

이제 1000장 정도 찍은 듯 한데. 아직 갈길이 먼 듯 해 보인다. 





블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

본가에서 점심을 먹고, 자취방으로 향하기 전에 서울 역사박물관에 들르기로 했다. 


서울 역사 박물관 앞 전차


지금은 사라진 홍제육교, 홍제고가차도, 아현고가차도 관련 물건


조이콤, 닌텐도의 슈퍼 패미콤과 호환된다.


소니 워크맨


해방 이후, 한반도에 진주한 연합군들을 환연하기 위한모습, 중국 국기가 특이하다.



왠만한 가정집에 하나씩은 있는 보일러 스위치, 목욕 눌러놓고 놀러나갔다고 혼났던 기억이 떠오른다. 



박물관 안에 있었던 1980 년대 가정집 모습.


하이텔 단말기, 이거 써보신분?



사진을 찍다보니 '찰칵찰칵' 하는 소리가 마음을 편하게 한다. 

작년 봄 이후, 마음이 이렇게 편안해져 본적은 처음이다. 

블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

판교, 화랑공원 가는길


안랩 앞 사거리에서  운중천, 포커스가 쉽게 잡히질 않는다.


근처에서 잠시 일 하다가, 오후 늦게 머릿속 정리 할 겸, 카메라를 들고 나선다.

Canon EOS 100D, 약 일주일 전에 구입한 DSLR 이다.

바로 찍은 구름의 모습, 화이트 밸런스 모드를 바꿔가면서 찍어봤지만, 배경이 어둡게 나오는건 어쩔 수 없는듯…


화랑공원에서 찍은 돌, 찍어보고 느낌이 좋아 룰루랄라 걷기 시작한다.


이때 시간은 오후 5시 15분 경, 해가 지기 시작한다.

하늘을 제외한 배경이 어두운건 어쩔 수 없지만, 찍고보니 나름 운치가 있다.



운중천 쪽으로 내려가면서, 풍경 사진은 좀더 많이 찍어봐야겠다. 집에서 컴퓨터로 보니 풀들이 전부 흐리게 나오는 느낌이다.


운중천에서 코트야드 매리엇 호텔을 바라보며, 화이트 밸런스를 태양광 세팅




화랑공원에서 돌무더기, 초점이 괜찮게 맞았다.


화랑공원 생태호수에서 바라본 유스페이스 & 엔씨소프트


같은 자리에서 바라본 코트야드 매리엇 호텔, 컨셉을 ‘숲 속의 도시’ 로 잡아보려 했지만, 쉽지 않다.


사진을 찍을 때 마다 나오는 '찰칵' 하는 소리, 계속 듣다보니 마음이 편해진다.

기분 전환 하러 자주 와야 겠다는 생각이 든다.



블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

며칠 전부터 엔터만 치면 광고가 떠댔는데,

귀찮고 회사일 바빠 참고 살다가 오늘 드디어 끝장을 봤다. 

프로세스 하나씩 죽이면서 테스트 해본 결과 

microlabcon.exe 혹은 microproproc.exe 이란 이름의 프로세스를 죽이니 같은 상황은 발생 안하더라... 

해결책 몇가지를 공유하자면 

1. 수동으로 직접 지우는 방법 

http://www.windowexe.com/bbs/board.php?bo_table=board01_m&wr_id=95

http://www.windowexe.com/bbs/board.php?bo_table=board01_m&wr_id=3064

실제로 해보니 심히 귀찮더라... 

몇가지 더 찾아보니 

2. 커맨드 창에서 삭제 명령어 입력

http://www.windowdel.com/bbs/board.php?bo_table=remove&wr_id=9

사람들이 하도 불펌을 해대서 자기 블로그에 '이거 내꺼임' 이짓을 해댔는지 

심히 복잡한 로직에 뭔소린지 알아내려 하다가 포기...

위 1번, 2번 방법은 일단 

어.느.순.간.엔.다.시.깔.려.있.다...

아예 차단할 수 있는 방법은 없을까 고민하다가....

예전에 시스템 속도가 전체적으로 느려져 지워버린 백신이 하나 떠올랐다.


avast!

일단 개인사용자용은 무료라길래 (물론 유료 모드도 있음)

사용하고있던 알약을 지운다음 무료모드 다운 후 설치,

머 하루안에 1년짜리 라이센스 키 준다는데 귀찮아서 유료모드(1000원 내면 바로 날아옴) 신청,

물론 avast 깔면 뭐 하나를 다시 깔라고..(지란지교소프트 인가? 거기서 만든거) 하는데...

깔았다가 지우니 별문제 안되더라....

여튼, 내 PC 설치 10분만에 avast! 가 돈값을 하기 시작한다.

인증키 바로 받는데 드는 1000원이 싸게 느껴질 정도의 빠닥빠닥한 반응들 

게임중엔 뜨지 않는 모드로 세팅 해놓으면 게임중에 방해도 없고 

띵띵 거리는 소리랑 화면이 좀 번거롭긴 하지만, 

일단 빌어먹을 광고는 안본다는거에 만족 하기로 했다. 

avast! 특정프로세스 강제종료기능 없나 찾아봐야겠다.

마지막으로 microlabcon 을 만드신 분께....

언제까지 날로먹을래?

난 저런거 설치하라고 동의한적 없어



블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
"다른사람이 만든것을 사용할때는 댓가를 지불하는게 당연하다" 를 간과한

성적중심 교육 덕분에 대한민국 게임판에서 벌어지는 상황

1. 패키지 게임 나와도 불법복제로 시망크리...
2. 초고속 인터넷 깔림
3. 2번의 여파로 돈을 안내면 할 수 없는 온라인게임 등장
4. 온라인 게임업체들의 급성장
5. 온라인 게임의 난립
6. "엔딩이 없는, 인간의 욕심을 끝없이 자극하는" 온라인게임의 특성상 과몰입 상태 시작
   6-1. 패키지 게임이 그나마 덜한건 "엔딩이 있음"(머.. 문명도 엔딩은 있음)
7. 게임중독자 양산
8. 여가부, 게임업체로부터 돈 뜯어낼 구실 찾아냄
9. 셧다운제 국회 통과될 기세.

지들이 교육 X같이 한 책임을 누구한테 묻는거야 이거?

블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
LuaJIT 2.0.x Beta 는 이전 버전과 달리 빌드과정이 좀 특이하다 
LuaJIT 1.x 버전처럼 MS Visual Studio(LuaJIT Doc 에는 MSVC 로 표기)에서 빌드해주면 include 파일이 없다는 에러가 난다. 

이유를 설명하기 앞서 LuaJIT 2.0.x 의 빌드과정은 다음과 같다.
 
1. msvcbuild.bat 파일을 살펴보면 처음에 헤더 파일을 작성하는 소스코드를 빌드 후 실행한다.
2. 위 1번에서 만들어진 헤더파일을 include 하여 다시 빌드한다. 
3. dll, exp, lib, exe 로 빌드된 파일을 만든다. 

2.0 버전을 MSVC에 몽땅 불러들여 컴파일 하는경우 2번 과정에서 사용할 헤더가 없다고 나온다. 

MSVC 에 넣고 컴파일 세팅을 변경하여 빌드시키는 방법도 있지만 이건 너무 복잡하고 

간단하게 해결하자 Microsoft Platform SDK 명령 프롬프트를 열고, 

LuaJIT 2.0.x 가 설치되어있는 폴더의 src 파일로 접근, 다음과 같은 명령어를 쳐준다. 

msvcbuild

텍스트 메시지가 주르륵 올라가며 깔끔하게 나온 exe, dll, lib, exp 파일을 확인 할 수 있다. 



블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

요즘들어 취미로 시작한 RunUO 스크립팅,
JACOB 님 으로부터 서버 크래시 발생 신고 접수
내 컴퓨터로 일단 돌려본 결과, 문제 발생안함,

상황은 대충 이렇다.
Bounty System 관련 스크립트를 적용 후 서버를 돌리면 세이브 타이밍에 크래시가 남,
메시지는...



Core: Using dual save strategy
World: Saving...Error:
System.Exception: World Save event threw an exception.  Save failed! ---> System.NullReferenceException: Object reference not set to an instance of an object
  at System.Data.XmlSchemaDataImporter.CreateChildColumn (System.Data.DataColumn parentColumn, System.Data.DataTable childTable) [0x00000]
  at System.Data.XmlSchemaDataImporter.GenerateRelationship (System.Data.RelationStructure rs) [0x00000]
  at System.Data.XmlSchemaDataImporter.Process () [0x00000]
  at System.Data.DataSet.ReadXmlSchema (System.Xml.XmlReader reader) [0x00000]
  at System.Data.DataSet.ReadXmlSchema (System.String fileName) [0x00000]
  at Server.BountySystem.BountyBoard.saveGlobalList (Server.WorldSaveEventArgs e) [0x00000]
  at (wrapper delegate-invoke) Server.WorldSaveEventHandler:invoke_void__this___WorldSaveEventArgs (Server.WorldSaveEventArgs)
  at (wrapper delegate-invoke) Server.WorldSaveEventHandler:invoke_void__this___WorldSaveEventArgs (Server.WorldSaveEventArgs)
  at (wrapper delegate-invoke) Server.WorldSaveEventHandler:invoke_void__this___WorldSaveEventArgs (Server.WorldSaveEventArgs)
  at Server.EventSink.InvokeWorldSave (Server.WorldSaveEventArgs e) [0x00000]
  at Server.World.Save (Boolean message) [0x00000]
  --- End of inner exception stack trace ---
  at Server.World.Save (Boolean message) [0x00000]
  at Server.World.Save () [0x00000]
  at Server.Misc.AutoSave.Save () [0x00000]
  at Server.Timer+DelayCallTimer.OnTick () [0x00000]
  at Server.Timer.Slice () [0x00000]
  at Server.Core.Main (System.String[] args) [0x00000]
Crash: Backing up...done
Crash: Generating report...done
Crash: Restarting...done





대충 이렇다...
리눅스용 C# 실행기(Mono) 에서 XSD 파일만 만나면 저런 오류를 뱉어내더라
결국 JACOB 님께 해당문제가 수정된 버전의 업그레이드를 제안...
하지만, 설치되어있는 버전은 이미 해당문제가 수정된 버전......

고심끝에 나중을 위해서라도 XML 로 되어있는 부분을 뜯어고치기로 결심...
회사일이 너무 바빠 구현은 힘들고 일단 생각만 정리해둔다.

Bounty System 의 경우 BountyBoard.cs 파일 안의 BountyBoard 클래스에서 현상금 정보를 관리한다..

m_Entries 정적변수 안에는 모든 현상금 정보가 기록되어 있으며, ArrayList 형태로 구성되어있다.
m_Entries ArrayList 안에 들어가는 객체 타입은 BountyBoardEntry 객체로, 현상금정보, 가해자, 피해자 정보 구성

크래시가 일어났던 부분은 BountyBoard 객체 안의 saveGlobalList 정적함수로 xsd 파일에 접근, xml 스키마를 읽어들이는 부분에서 나는것으로 확인되었다.

2010년 4월 7일 현재, XML 대신 DB 로 저장하여 관리하는게 차후 랭킹 시스템 구현에서 용이함을 가져오고, 해당 크래시 문제를 해결할 수 있으리라고 본다.

DB 로 구현할때 필요한건 다음과 같다.

테이블 : (Owner Name, Owner Serial, Wanted Name, Wanted Serial, Price) 컬럼 필요
저장함수 기능 : Bounty 일괄추가, Bounty 일괄삭제, 유저별 합산 Bounty 및 순위 매기기

회사 일이 조금 한가해 지는대로 작업 시작한다.
블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
과연 LuaJIT 가 2~10배 정도 속도가 나온다 나온다 말만 듣다가
이제서야 테스트를 해봅니다.
결과부터 말씀드리자면 상당히 놀라운 결과였습니다.

일단 테스트용 Lua 코드는 다음과 같습니다.

function TrafficTest()
    for i = 0 , 10000, 1 do       
        iii = i * i*i*i*i*i*i*i*i*i*i*i   
    --중략, iii = i * i*i*i*i*i*i*i*i*i*i*i 와 같은 코드가 200라인 정도 있습니다.
    end
end

테스트한 C++ 코드는 다음과 같습니다.

루아 팅커를 사용하여 lua 함수를 호출하였습니다.

int _tmain(int argc, _TCHAR* argv[])
{
    lua_State *L = lua_open();   
    luaL_openlibs(L);   
    int Start, End;
    printf("LuaJIT Performance Test\n");

   
    printf("case one, LuaJIT is activated\n");
    //LuaJIT on, 디폴트 상태로 켜져있지만 명시적으로 한번 더 넣어주고 한다.
    luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE|LUAJIT_MODE_ON);
    lua_tinker::dofile(L, "TestFunction.lua");

    Start = GetTickCount();

    //루프의 수를 10, 100, 1000 순서대로 늘려가면서 복잡도를 증가시켰습니다.
    for (int i = 0; i < 10; i++)   
    {
        lua_tinker::call<void>(L, "TrafficTest");
    }   
    End = GetTickCount();
    printf("Process Time : %d\n", End - Start);

   
    //Case Two JIT off
   
    printf("case two, LuaJIT is deactivated\n");
    luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE|LUAJIT_MODE_OFF);   
    lua_tinker::dofile(L, "TestFunction.lua");

    Start = GetTickCount();
    //루프의 수를 10, 100, 1000 순서대로 늘려가면서 복잡도를 증가시켰습니다.
    for (int i = 0; i < 10; i++)   
    {
        lua_tinker::call<void>(L, "TrafficTest");
    }
    End = GetTickCount();
    printf("Process Time : %d\n", End - Start);
    return 0;
}

결과는 경이적이다 못해 충격적(일천한 제 경험 탓 일수도 있습니다만, 이게 과연 스크립트언어인가 할 정도로)입니다.

10(c 루프 횟수) x 10000(lua 루프 횟수)



100(c 루프 횟수) x 10000(lua 루프 횟수)



1000(c 루프 횟수) x 10000(lua 루프 횟수)



서버/클라이언트 클라이언트를 막론하고, Lua 를 사용하며 속도상의 이점을 가져오는게
좋을 듯 합니다.

'프로그래밍' 카테고리의 다른 글

Three.js Object Load 방법  (0) 2020.11.21
블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

곰티비에서 했던 이벤트에 운좋게 당첨이 되어 곰리모컨 POP 을 받았습니다.


왼쪽이 지금까지 제가 사용해왔던 곰리모컨, 오른쪽에 이번에 새로 받게 된 곰리모컨 팝 입니다.

 

기존의 TV 리모컨 모양이었던 곰 리모컨(아마 곰티비 사용자들의 편의를 위해 만들었다고 예상됩니다.) 과는 다르게, 크게 쓰이지 않는 부분을 과감하게 잘랐습니다. 

 곰리모컨과 곰리모컨 팝, 손에 들어올 정도의 크기로 작아졌습니다.

 

 

 

 

곰 리모컨 본체입니다. 전체적인 버튼 모양이 곰티비의 마크를 연상시키네요


이번 버전에서는 많은 기능을 담기 보다는 아기자기 한 면을 강조한거 같아보입니다.


버튼을 눌렀을 때 사진입니다. 가운데 버튼에 불이 들어옵니다.

 


뒷면 사진입니다. 메탈 톤으로 깔끔한 느낌입니다.



기존의 곰리모컨과는 다르게 수은전지가 들어갑니다. 작은 크기를 위한 선택같네요
 

심플한 인터페이스, 기능적 아쉬움

결과부터 말하자면, 처음엔 곰 리모컨 Pop 을 사용하다가 지금은 다시 기존의 곰 리모컨을 사용하고 있습니다. 기존 버전에는 있었지만, Pop 버전에는 없는 것, 바로 아날로그 스틱 때문인데요아날로그 스틱에 길들어져 있는 저는 곰 리모컨 팝의 버튼에 적응이 힘들었습니다. 이건 개인적인 생각이지만 곰리모컨에 G-센서 기술을 적용시키는것도 나쁘진 않을거 같아 보입니다.



바로 요녀석, 요녀석 덕분에저로 하여금 곰리모컨을 끊지 못하게 하는 아날로그스틱

 

곰티비의 여러가지 실험, 그리고 곰 리모컨

기능적 편리함(다운로드와 동시에 감상 가능!)때문에 곰플레이어를 사용하고, 곰티비를 사용하게 되었던 저는, 곰리모컨 팝도 최고를 향해 성장해 나가는 하나의 과정이라 봅니다. 이러한 과정들이 모여서 하나의 큰 성공이 이루어질것이란 생각이 듭니다. 곰리모컨 Pop 의 기능은 다소 실망스러웠지만, 지금부터 다음 버전에 대한 기대감이 생깁니다. 다음에는 더 멋진 기능으로 나오길 바랍니다.

블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Visual Studio 2008 C# 컴파일러 생성 문제


아마 Visual Studio 2008을 설치 한 후, Visual Studio 2005 를 삭제했을 때, 문제가 발생하는듯합니다. 연구실에서 WPF 관련 세미나를 준비하면서 이런 현상을 겪었는데 해결책을 찾았습니다.

C# 관련 프로젝트를 열거나 새로 생성했을 때 다음과 같은 에러가 발생하면서 C# 파일이 열리지 않는데요

 

Microsoft Visual C# 2008 Compiler could not be created. QueryService for '{7D960B16-7AF8-11D0-8E5E-00A0C911005A} failed.

 

맨 처음에는 .net Framework 문제로 알고 .net Framework 삭제를 위해 동분서주 했지만 결국 실패, 구글과 MSDN 을 검색한 후 찾은 해결책 입니다.

 

1.     먼저 심호흡을 한번 크게 합니다 (긴장을 풀자고요!!)

2.     시작->프로그램->Microsoft Visual Studio 2008->Visual Studio Tools->Visual Studio 2008 Command Prompt 를 실행합니다.

3.     그러면 커맨트 창이 하나 나타나게 되는데요 거기에 다음과 같이 입력합니다.

devenv /ResetSkipPkgs

 

실행을 하게 되면 Visual Studio 2008 이 실행되면서 모든 패키지들을 초기화합니다.

이렇게 해준 후 C# 프로젝트들이 정상적으로 로딩 되는 모습을 보실 수가 있으리라 생각 됩니다.

만약 이렇게 해도 해결되지 않는다면… Visual Studio 2008 및 관련 프로그램 모두를 삭제 후 재설치 한 다음

다시 해봅니다. 그래도 되지 않는다면....

 

별수 없습니다…. 포맷 하는수밖에….

블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
우연한 기회에 프로그래밍 루아 검토작업에 참여했었습니다.

벌써 1년이나 지났네요...

그때 기념으로 받은 책은 아직도 제 책상위에 있답니다.
블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Visual C++ 2008의 파일읽기 버그

졸업프로젝트를 하다 이상한 현상을 목격했습니다.

이 현상 덕분에 4시간동안 아무것도 못했으니 어떻게 보면 실로 엄청난 문제같은데..

누군가에게 도움이 되고자 이렇게 만듭니다.

 

흔히 MFC 에서 파일을 읽어들일 때, CFile 을 사용합니다.

 

CFile::Read() 라는 함수를 보면 파일에 있는 내용을 읽어들이는 버퍼로 LPVOID 형 변수를 사용하는데요 보통 char 형 포인터를 캐스팅해서 사용합니다.

 

TCHAR Cost2[512];

file.Read((LPVOID)Cost2, 512);

 

MFC 에서 문자열을 위한 CString 클래스를 제공하는데 이를 사용하기 위해선

 

CString Cost2;

file.Read((LPVOID)(LPCTSTR)Cost2, file.GetLength());

 

이렇게 해줍니다. 문제는 여기서 발생합니다. CString 2개이상 선언(클래스 내부 혹은 구조체 내부 건 위치는 상관 없습니다.)해서 이를 이용해 파일 내용을 읽어들이면

사용자 삽입 이미지

위와 같은 내용을 가진 변수들이
사용자 삽입 이미지

 

이렇게 바뀝니다이런

문제는 이것 뿐만이 아닙니다.

사용자 삽입 이미지

컨트롤에 있는 변수(내용이 비어있을 것이라고 추정)는 죄다 해당 내용으로 바뀝니다. 위의 변수는 VS 2008 Feature Pack 에서 지원되는 그리드 클래스안의 변수입니다. 저렇게 되어있는 변수를 윈도우 클래스에 붙여주게 되면 당연히런타임 에러가 발생합니다.

따라서, CFile:Open 안의 데이터 내용을 문자열로 읽어들이려면

1.     TCHAR 를 사용한다.

2.     CString 을 사용하고 싶거든 실행되는 모든 객체에 대해서 파일을 읽어들인 후 일일히 초기화를 시켜줘라..(확인된 방법은 아님, 실제로 해보다가 지쳐서포기)

를 해주는게 추후 정신건강에 좋다고 생각됩니다.

2008 6 15일 박지훈씨의 의견에 의한 내용 추가

CString 의 선언 후 Debug를 통해 포인터를 조사해 보았습니다. 그 결과

사용자 삽입 이미지

CString 으로 선언된 두 변수 aa, bb 가 같은곳을 가리키고 있음을 확인할 수 있습니다.

따라서, 생각해보건데 CString 은 대입 연산이 일어날 때, 메모리를 새로 할당받아서 사용함을 생각할 수 있습니다.

 

'프로그래밍 > MFC&API' 카테고리의 다른 글

Windows Via C/C++  (0) 2008.05.21
MFC RTTI (CRuntimClass)  (2) 2008.05.20
블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
사용자 삽입 이미지

Programming Applications for Microsoft Windows 가 5 판이 나왔습니다.
그동안 지원이 중단되었던 MFC 와 운명을 같이하는것처럼 상당히 오랜만에 나왔는데요..
책을 구하다 못해 겨우 제본판으로만 구해 보고 있던 저에게는 상당한 희소식이었습니다.
교보에 6만우너 가까이 주고 해외주문을 했는데 막상 책을 받아보고 나니 돈이 전혀 아깝지가 않더라고요..
현재는 4장 프로세스 부분까지 읽고 있는데 읽으면 읽을수록 무엇인가 Windows 에 대한 비밀이  하나씩
벗겨지는 느낌입니다.
윈도우 개발자를 목표로 공부하시는 분들은 꼭 한번씩 읽어보아야 할 정도로 명작입니다.

'프로그래밍 > MFC&API' 카테고리의 다른 글

Visual C++ 2008의 파일읽기 버그  (0) 2008.06.15
MFC RTTI (CRuntimClass)  (2) 2008.05.20
블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

RTTI(Run-Time Type Information)

JAVA 와는 달리 C++ 에서는 RTTI를 완벽하게 지원하지 않습니다. 때문에 MS Compiler 차원에서 RTTI를 지원해주기 위한 방법을 구현해냈는데 그게 CRuntimeClass 와 여러가지 매크로함수를 제공하고 있습니다. 오늘은 이에대해 알아보겠습니다.

 

먼저 RTTI MFC 에서 지원하게 하려면 다음과 같은 규칙이 필요합니다.

1.     클래스는 반드시 CRuntimeClass 타입의 static 멤버를 갖고 있어야 한다.

A.     CRuntimeClass는 객체를 생성하기 전, 클래스 레벨에서 접근해야 한다
.

2.     1 에 선언된 static 멤버를 초기화하는 루틴을 구현파일에 가져야 한다.

A.     초기화 루틴은 클래스 이름, 클래스 크기를 설정하고, CRuntimeClass::m_pfnCreateObject를 클래스의 정적 멤버 함수 CreateObject 로 초기화한다.

3.     클래스는 반드시 CObject * 를 리턴하는 정적 CreateObject 함수를 선언해야 한다.

A.     클래스 레벨에서 접근해야 하므로 static 이어야 한다

4.     3 에 선언된 static 멤버 함수의 몸체를 구현파일에 가져야 한다.

A.     CreateObject 는 자기 자신을 동적으로 생성하고, 생성된 객체의 시작 주소를 리턴한다.

 

MFC 소스를 분석해 나가다보면 다음과 같은 코드를 종종 볼 수 있습니다.

RUNTIME_CLASS(CLOVE_JAENAMDoc)

DECLARE_DYNCREATE(CLOVE_JAENAMView)

IMPLEMENT_DYNCREATE(CLOVE_JAENAMView, CView)

 

그리고 다음과 같은 클래스도 볼 수 있습니다.

CRuntimeClass

 

먼저 CRuntimeClass 구조체를 살펴보면

 

struct CRuntimeClass

{

// Attributes

        LPCSTR m_lpszClassName;

        int m_nObjectSize;

        UINT m_wSchema; // schema number of the loaded class

        CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class

#ifdef _AFXDLL

        CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();

#else

        CRuntimeClass* m_pBaseClass;

#endif

 

// Operations

        CObject* CreateObject();

        BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;

 

        // dynamic name lookup and creation

        static CRuntimeClass* PASCAL FromName(LPCSTR lpszClassName);

        static CRuntimeClass* PASCAL FromName(LPCWSTR lpszClassName);

        static CObject* PASCAL CreateObject(LPCSTR lpszClassName);

        static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);

 

// Implementation

        void Store(CArchive& ar) const;

        static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);

 

        // CRuntimeClass objects linked together in simple list

        CRuntimeClass* m_pNextClass;       // linked list of registered classes

        const AFX_CLASSINIT* m_pClassInit;

};

 

상당히 많은 양의 코드가 있는데 놀라지 말고 간단하게 몇가지만 살펴보고 넘어갈껍니다.

먼저 속성 부분에는 클래스 이름, 클래스 크기, 현재 스키마의 번호를 갖고 있습니다.

// Attributes

        LPCSTR m_lpszClassName; // 클래스 이름

        int m_nObjectSize; // 클래스 크기

        UINT m_wSchema; // 클래스 스키마 번호

        CObject* (PASCAL* m_pfnCreateObject)(); // 기본생성자의 함수 포인터

생성자의 함수 포인터를 가리키는게 약간 특이합니다만, 이부분에 대해서는 나중에 자세히 설명을 할 것이니, 지금은 동적 생성을 지원하기 위해 사용하는 거라고 간단히 알고 넘어갑시다.

다음은 전처리기 부분입니다.

#ifdef _AFXDLL

        CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();

#else

        CRuntimeClass* m_pBaseClass;

#endif

 

먼저 _AFXDLL 에 대해 간단하게 설명하자면, MFC 에서 빌드할 때 MFC 관련 라이브러리 (보통 AFX 로 시작하는..)를 어떻게 링크할 것인가를 물어보는 옵션이 있습니다. 동적으로 링크했을 경우는  _AFXDLL define 상태가 되고, 정적링크를 할 경우에는 _AFXDLL undefine 상태가 됩니다 따라서 동적 링크 시에는

CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();

정적 링크 시에는

CRuntimeClass* m_pBaseClass;

부분이 실행이 됩니다.

 

다음으로 함수 몇 개가 더 나옵니다.

 

// Operations

        CObject* CreateObject();

        BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;

 

먼저 RTTI를 지원하는 클래스는 CObject 에서 상속을 받아야 합니다. 그 이유는 지금 CreateObject() 함수처럼 동적으로 클래스를 생성해야 하기 때문이져… CreateObject 함수는 해당 객체를 동적으로 생성해주는 함수 입니다. 여기서 잠깐!! 지금까지의 코드는 함수의 포인터나 객체의 포인터를 사용해서 연결을 시킨 후 함수를 실행해주는데 지금의 함수 구현부는 어디있나요? 정답은 잠시후에 알 수 있을 것입니다. 잠시만 참아주세요

 

다음으로 IsDerivedFrom 함수는 인자로 받은 클래스가 현재 클래스의 상위클래스인지를 검사하는 함수입니다. 리턴값은 당연히, 상속관계면 TRUE, 아니면 FALSE 가 되겠져?

 

그 다음부분은 저도 잘 모르고…(후다닥;;;)

 

이젠 이렇게 구현해놓은 CRuntimeClass 를 실제로 어떻게 사용하는지 보겠습니다.

일단, SDI MDI MFC 프로젝트를 하나 만들어 두시고 다음을 계속 읽어내려가 주세요

저는 VS 2008 사용자라 이런저런 클래스가 많이도 생기네요

일단 2005에서도 익숙했던 도큐먼트 클래스를 보도록 하겠습니다.

헤더파일을 보면 다음과 같은 매크로 함수가 버티고 있습니다.

DECLARE_DYNCREATE(CLOVE_JAENAMDoc)

맨 처음 MFC를 접하면 수도없이 많은 매크로 함수 때문에 상당한 혼돈이 오게 되는데, 당황하지 마시고 천천히 뜯어보면 됩니다, 그러면 지금부터 저 히한하고 요상하게 생긴 매크로 함수부터 뜯어보겠습니다.

DECLARE_DYNCREATE(CLOVE_JAENAMDoc) 의 원형은 다음과 같습니다.

#define DECLARE_DYNCREATE(class_name) \

        DECLARE_DYNAMIC(class_name) \

        static CObject* PASCAL CreateObject();

 

즉 다음과 같은 매크로 함수가

DECLARE_DYNCREATE(CLOVE_JAENAMDoc)

컴파일시에는 다음과 같은 코드로 바뀝니다.

DECLARE_DYNAMIC(class_name)

static CObject* PASCAL CreateObject();

 

DECLARE_DYNAMIC(class_name) 의 원형은

 

#define DECLARE_DYNAMIC(class_name) \

protected: \

        static CRuntimeClass* PASCAL _GetBaseClass(); \

public: \

        static const CRuntimeClass class##class_name; \

        static CRuntimeClass* PASCAL GetThisClass(); \

        virtual CRuntimeClass* GetRuntimeClass() const; \

이므로 DECLARE_DYNCREATE(CLOVE_JAENAMDoc) 는 최종적으로

다음과 같은 코드로 바뀝니다

protected:

        static CRuntimeClass* PASCAL _GetBaseClass();

public:

        static const CRuntimeClass classCLOVE_JAENAMDoc;

        static CRuntimeClass* PASCAL GetThisClass();

        virtual CRuntimeClass* GetRuntimeClass() const;

           static CObject* PASCAL CreateObject();

, 그러면 여기서 RTTI를 사용하기 위한 규칙 1, 3번 을 떠올려봅시다!!

클래스는 반드시 CRuntimeClass 타입의 static 멤버를 갖고 있어야 한다

클래스는 반드시 CObject * 를 리턴하는 정적 CreateObject 함수를

선언해야 한다.

 

어때요? 참 쉽죠? (밥 아저씨가 생각나네요) 현재 클래스의 정보를 갖고있는 CRuntimeClass의 포인터를 얻어내는 함수를 제외하면 1번과 3번의 조건을 매크로 함수 하나로 처리를 해주고 있습니다

 

그러면 눈치빠른 분들은 이미 아시겠져? 다음은 무얼 할껀지

구현부분에서 어떻게 되어있는지 보겠습니다. 이제 남은 규칙은 두가지네요

 

1 에 선언된 static 멤버를 초기화하는 루틴을 구현파일에 가져야 한다.

3 에 선언된 static 멤버 함수의 몸체를 구현파일에 가져야 한다.

 

구현부분도 역시 매크로 함수 하나로 다해주고 있는게 보이네요

 

IMPLEMENT_DYNCREATE(CLOVE_JAENAMDoc, CDocument)

 

이 매크로 함수가 어떻게 정의되는지 보겠습니다.

 

#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \

        CObject* PASCAL class_name::CreateObject() \

               { return new class_name; } \

        IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \

               class_name::CreateObject, NULL)

 

그리고 IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \

               class_name::CreateObject, NULL) 는 다시

 

CRuntimeClass* PASCAL class_name::_GetBaseClass() \

               { return RUNTIME_CLASS(base_class_name); } \

AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \

        #class_name, sizeof(class class_name), wSchema, pfnNew, \

               &class_name::_GetBaseClass, NULL, class_init }; \

CRuntimeClass* PASCAL class_name::GetThisClass() \

        { return _RUNTIME_CLASS(class_name); } \

CRuntimeClass* class_name::GetRuntimeClass() const \

        { return _RUNTIME_CLASS(class_name); }

 

로 정의되고 있습니다. 따라서 IMPLEMENT_DYNCREATE(CLOVE_JAENAMDoc, CDocument)

CObject* PASCAL class_name::CreateObject()

        { return new CLOVE_JAENAMDoc; }

 

CRuntimeClass* PASCAL CLOVE_JAENAMDoc::_GetBaseClass()

        { return RUNTIME_CLASS(CDocument); }

 

AFX_COMDAT const CRuntimeClass CLOVE_JAENAMDoc::classCLOVE_JAENAMDoc = {

        CLOVE_JAENAMDoc, sizeof(class CLOVE_JAENAMDoc), wSchema, pfnNew,

               & CLOVE_JAENAMDoc::_GetBaseClass, NULL, class_init };

 

CRuntimeClass* PASCAL CLOVE_JAENAMDoc::GetThisClass()

        { return _RUNTIME_CLASS(CLOVE_JAENAMDoc); }

 

CRuntimeClass* CLOVE_JAENAMDoc::GetRuntimeClass() const

        { return _RUNTIME_CLASS(CLOVE_JAENAMDoc); }

 

로 다소 복잡하게 바뀌지만 헤더에서 선언한 부분을 모두 구현해주고 있습니다.

마지막으로 RUNTIME_CLASS(CLOVE_JAENAMDoc),_RUNTIME_CLASS(CLOVE_JAENAMDoc) 는 다음과

같이 정의됩니다.

 

#define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))

#ifdef _AFXDLL

#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())

#else

#define RUNTIME_CLASS(class_name) _RUNTIME_CLASS(class_name)

#endif

정리하자면, _RUNTIME_CLASS(class_name) 는 현재 클래스의 이름을, 직접 리턴해주고

RUNTIME_CLASS(class_name) 은 간접적으로 _RUNTIME_CLASS(class_name) 를 호출하여 현재 클래스를 리턴해줍니다

 

이상 RTTI MFC 에서 어떻게 구현이 되어있는지 알아봤습니다.

SDI MDI 의 소스를 찬찬히 뜯어보게되면 RUNTIME_CLASS 같은 매크로 함수는 많이 보게 되니 이해하시는데 도움이 되었으면 좋겠습니다.

'프로그래밍 > MFC&API' 카테고리의 다른 글

Visual C++ 2008의 파일읽기 버그  (0) 2008.06.15
Windows Via C/C++  (0) 2008.05.21
블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

새로운 컴퓨터 문화의 중심

1974년 우리나라에 컴퓨터가 들어오기도 전, 컴퓨터란 개념을 널리 알리고자 다섯 학교 학생들이 모임을 만들었다. 이것이 전국 대학생 컴퓨터 동아리 연합인 '유니코사' (UNIversity COmputer Science Association)의 시초다. 29년을 이어왔기에 그간 유니코사를 거쳐 간 회원수가 10만명에 이른다. 걸출한 선배도 많아 배출됐는데 HNI 최연규, DREAMWIZ 이찬진, 그레텍 송길섭, CCR 윤석호씨 등이 유니코사 출신이다.

컴퓨터 동아리는 어느 학교에나 있다. 그런데 새삼 그들이 연합해서 활동하는 이유는 뭘까. "컴퓨터 동아리 연합이라고 해서, 회원 학교 간의 친목 도모가 목적의 전부는 아니에요. 그보다 컴퓨터가 좋아서 모인 대학생이, 다른 이들을 위해 할 수 있는 게 무엇인가를 고민해 실천하는 것이 저희 동아리의 주된 목적이죠. 그러기 위해선 한 학교의 힘만으로는 부족하잖아요. 컴퓨터 동아리는 학교마다 다 있으니까 함께 모이면 큰 힘이 돼요. 여러 학교가 모이면 많은 사람들을 대상으로 하는 큰 행사를 열 수 있으니까요."

우연주(동덕여대 컴퓨터 02)씨의 대답처럼 그들의 행사는 제법 굵직하다. 매년 고정적으로 여는 행사만도 시무식, 연합 강연회, 연합 M·T, 연합 전시회, 체육 대회, 창립제, 세미나 등 다양하다. 이를 통해 컴퓨터 동아리 간의 정보를 교류하고 친선을 도모하며, 일반인에게 컴퓨터에 관한 유익한 정보를 제공한다.


올 가을, 컴퓨터 관련 다양한 행사 열어

9월초에 있을 '제 1회 모바일 세미나'는 새롭게 준비하는 행사다. 이제껏 해오던 세미나는 전문적인 내용이 많아, 일반인보다는 회원 학교가 대상이었다. 그러나 이번에는 일반인을 대상으로, 누구나 쉽게 이해할 수 있는 세미나를 열기로 했다. 주제 역시, 최근 관심이 높은 모바일로 정했다. 예상 참가 인원은 천명 정도로, 큰 규모의 세미나다.

"컴퓨터에 관한 정보를 좋은 환경에서 많은 사람에게 제공하고 싶어 계획했어요. 무료 행사니까, 관심 있으시면 부담 없이 들으시면 돼요. 특히 관련된 업종에 취업하려는 분이나 처음 모바일을 접하는 분에게 좋은 기회가 될 것 같아요." 신종혁(항공대 통신 02)씨가 이번 세미나에 대해 덧붙이는 말이다.

또 10월에 있을 연합 전시회에서는 회원 학교들이 각 학교 축제에서 선보인 전시물을 한자리에 전시하는 것 이상의 특별한 이벤트를 선보일 예정이다. 무료로 고장난 컴퓨터 고쳐주는 행사와 무료 컴퓨터 게임 제공, 다양한 먹거리 장터는 예전 연합 전시회에서도 호응이 좋았다고. 이번에는 컴퓨터게임 대회도 개최할 예정이다.

"많은 사람이 컴퓨터를 부담 없이 즐길 수 있는 자리로 만들 생각입니다. 노래나 춤, 술이나 음악이 고전적인 축제의 한 요소였다면, 우리 축제에는 컴퓨터가 그 자리를 대신하는 거죠." 이황춘(수원대 컴퓨터 02)씨의 말처럼, 달콤하고 흥겨울 연합 전시회의 모습이 자못 궁금하다.


개발자서 사용자 중심으로

1980년대 유니코사의 활동 목표는 '컴퓨터 마인드의 확산'이었다. 그러나 시대가 변함에 따라, 유니코사의 활동 목표 역시 바뀌었다. 21세기에 서있는 지금, 유니코사가 내세우는 목표는 '컴퓨터의 신문화 정착과 확산운동'이다. 개발자 중심의 컴퓨터 문화에서 벗어나 사용자 중심의 컴퓨터 문화로 가는 시대를 반영한 것이다. 이같은 목표아래, 1999년 '유니코사 주최 벤처 창업 공모전'을 개최한 바 있다. 그러나 생각보다 호응이 적어 계속 이어지지 못했다.

현재는 '컴활'(컴퓨터 정보화 활동)과 '올바른 인터넷 언어문화를 위한 캠페인'을 계획중이다. 소외된 계층의 컴퓨터 교육을 위한 '컴활'은 확산운동, '올바른 인터넷 언어문화를 위한 캠페인'은 컴퓨터 신문화 정착의 일환이다. 캠페인은 새로 단장중인 홈페이지가 열리면 거기서부터 시작할 예정이란다. 또 지금 추진 중인 연합 스터디를 통해 학술 교류를 꾸준히 이어나갈 생각이다. 전문적인 것보다는 실용적인 주제 위주로 스터디를 활성화시킬 계획을 갖고 있다. 이런 노력이 결실을 맺어 새로운 컴퓨터 문화를 이끌어 가는 파워 유저 그룹, 유니코사가 되길 기대해 본다.

홈페이지 http://unicosa.or.kr


권상현 회장·숭실대 산업정보시스템 01


준비중인 행사들이 잘 마무리됐으면 좋겠어요. 지금 세미나와 연합 전시회 준비가 한창인데, 일반인을 대상으로 여는 행사라 호응이 많았으면 하네요. 또 지금 계획하고 있는 것이 많거든요. 새롭게 추가하려는 행사에 대해서도 구상중이고요. 이런 행사에 더 많은 사람이 함께 참여했으면 좋겠어요. 그렇게 되면 지금 하고 있는 것이 그저 하나의 행사에 그치는 것이 아니라, 하나의 문화로 자리 잡을 수 있을 거라고 생각합니다.

조지영 학생리포터 badai01@hanmail.net

블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,