반응형

http://msdn.microsoft.com/ko-kr/library/windows/desktop/ms682483(v=vs.85).aspx








Creates a queue for timers. Timer-queue timers are lightweight objects that enable you to specify a callback function to be called at a specified time.



Syntax

HANDLE WINAPI CreateTimerQueue(void);

Parameters

This function has no parameters.

Return value

If the function succeeds, the return value is a handle to the timer queue. This handle can be used only in functions that require a handle to a timer queue.

If the function fails, the return value is NULL. To get extended error information, callGetLastError.






Remarks

To add a timer to the queue, call the CreateTimerQueueTimer function. To remove a timer from the queue, call the DeleteTimerQueueTimer function.

When you are finished with the queue of timers, call the DeleteTimerQueueEx function to delete the timer queue. Any pending timers in the queue are canceled and deleted.

To compile an application that uses this function, define _WIN32_WINNT as 0x0500 or later. For more information, see Using the Windows Headers.



BLOG main image

0x0500 은 윈도우 2000 을 말한다, XP 보다도 낮은버전

Windows XP =_WIN32_WINNT>=0x0501

WINVER>=0x0501

Windows 2000 =_WIN32_WINNT>=0x0500

WINVER>=0x0500



 









An application-defined function that serves as the starting address for a timer callback or a registered wait callback. Specify this address when calling theCreateTimerQueueTimerRegisterWaitForSingleObject function.

The WAITORTIMERCALLBACK type defines a pointer to this callback function.WaitOrTimerCallback is a placeholder for the application-defined function name.

Syntax

VOID CALLBACK WaitOrTimerCallback(
  _In_  PVOID lpParameter,
  _In_  BOOLEAN TimerOrWaitFired
);

Parameters

lpParameter [in]

The thread data passed to the function using a parameter of theCreateTimerQueueTimer or RegisterWaitForSingleObject function.

TimerOrWaitFired [in]

If this parameter is TRUE, the wait timed out. If this parameter is FALSE, the wait event has been signaled. (This parameter is always TRUE for timer callbacks.)

Return value

This function does not return a value.

Remarks

This callback function must not call the TerminateThread function.

For an example that uses this callback function, see Using Timer Queues.

Requirements

Minimum supported client

Windows XP [desktop apps only]

Minimum supported server

Windows Server 2003 [desktop apps only]

Header

WinBase.h on Windows XP, Windows Server 2003, Windows Vista, Windows 7, Windows Server 2008, and Windows Server 2008 R2 (include Windows.h);
Winnt.h on Windows 8 and Windows Server 2012



 







예제


#include <windows.h>
#include <stdio.h>

HANDLE gDoneEvent;

VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
    if (lpParam == NULL)
    {
        printf("TimerRoutine lpParam is NULL\n");
    }
    else
    {
        // lpParam points to the argument; in this case it is an int

        printf("Timer routine called. Parameter is %d.\n", 
                *(int*)lpParam);
        if(TimerOrWaitFired)
        {
            printf("The wait timed out.\n");
        }
        else
        {
            printf("The wait event was signaled.\n");
        }
    }

    SetEvent(gDoneEvent);
}

int main()
{
    HANDLE hTimer = NULL;
    HANDLE hTimerQueue = NULL;
    int arg = 123;

    // Use an event object to track the TimerRoutine execution
    gDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (NULL == gDoneEvent)
    {
        printf("CreateEvent failed (%d)\n", GetLastError());
        return 1;
    }

    // Create the timer queue.
    hTimerQueue = CreateTimerQueue();
    if (NULL == hTimerQueue)
    {
        printf("CreateTimerQueue failed (%d)\n", GetLastError());
        return 2;
    }

    // Set a timer to call the timer routine in 10 seconds.
    if (!CreateTimerQueueTimer( &hTimer, hTimerQueue, 
            (WAITORTIMERCALLBACK)TimerRoutine, &arg , 10000, 0, 0))
    {
        printf("CreateTimerQueueTimer failed (%d)\n", GetLastError());
        return 3;
    }

    // TODO: Do other useful work here 

    printf("Call timer routine in 10 seconds...\n");

    // Wait for the timer-queue thread to complete using an event 
    // object. The thread will signal the event at that time.

    if (WaitForSingleObject(gDoneEvent, INFINITE) != WAIT_OBJECT_0)
        printf("WaitForSingleObject failed (%d)\n", GetLastError());

    CloseHandle(gDoneEvent);

    // Delete all timers in the timer queue.
    if (!DeleteTimerQueue(hTimerQueue))
        printf("DeleteTimerQueue failed (%d)\n", GetLastError());

    return 0;
}




 


반응형
반응형

BLOG main image






 닫기버튼(x닫기)이나 alt+F4 종료하게되면


WM_CLOSE 메세지가 프레임 윈도우에 발생한다


mainframe::OnClose() 함수가 먼저 호출됨










http://blog.naver.com/hoi_yeon/10020732860


WM_CLOSE

윈도우가 닫히기 전에 이 메세지가 전달되며 메인 윈도우인 경우는 응용 프로그램이 종료된다는 신호.

이 메세지를 처리하지 않고 DefWindowProc으로 보내면 DestroyWindow 함수를 호출하여 윈도우를 파괴하도록한다.

이 메제지가 전달되었을 때는 아직 윈도우가 파괴된 것이 아니므로 윈도우가 파괴되는 것을 중간에 차단할 수 있다. 미저장 파일이 있거나 프로그램을 종료할 상황이 되지 않을때 사용자에게 메세지 박스를 통해 종료 사실을 확인 시킬수 있으며 이 메세지를 가로채서 단순히  return하면 DestroyWindow가 호출되지 않도록 할 수 있다.

WM_DESTROY

윈도우가 파괴될 때 이 메세지가 전달된다. 사용자가 Alt+F4 또는 닫기버튼을 누를 경우 WM_CLOSE 메세지가 전달되며 이 메세지를 별도로 처리하지 않으면 DefWindowProcDestroyWindow함수를 호출하여 윈도우를 파괴한다. 또는 프로그램 코드 내부에서 명시적으로  DestroyWindow함수를 호출할 때도 윈도우가 파괴되는데 이 함수 호출결과로 WM_DESTROY 메세지가 전달된다.

이 메세지를 받은 윈도우의 종료를 위한 처리를 해야 하는데 예를 들어 열어놓은 파일을 닫고 할당한 메모리를 해제하는 등의 정리 작업을 한다. WM_CREATE에서의 초기화 처리의 반대 동작이 이 메세지에 작성되는것이 일반적이며 그 외 레지스트리에 미보관 정보를 저장하는 등의 작업을 할 수 있다. 만약 파괴되는 윈도우가 클립보드 체인에 속해 있으면 자신을 클립보드 체인에서 제거해야한다.

DestroyWindow 함수는 파괴할 윈도우를 화면에서 숨긴 후 이 메세지를 보내므로 이 메세지를 받은 시접에서는 윈도우 자체가 파괴되지 않은 상태이다. 또한 DestroyWindow 함수는 자식 윈도우에게도 이 메세지를 차례대로 보내주는데 부모 윈도우가 먼저 이 메세지를 받고 자식 윈도우에게로 이 메세지가 보내진다. 따라서 부모 우니도우가 이 메세지를 처리하는 동안은 모든 자식 윈도우가 아직 파괴되기 전이므로 자식 윈도우를 프로그래밍할 수 있다.

파괴되는 윈도우가 메인 윈도우일 경우 PostQuitMessage 함수르 ㄹ반드시 호출하여 프로세스의 메시지 루프를 종료하도록 해야 한다. 만약 이 처리를 생략하면 윈도우만 파괴되고 메세지 루프는 계속 실행중인 상태가 되므로 프로세스가 종료되지 않는다.

 

출처 - www.winapi.co.kr

[출처] WM_CLOSE / WM_DESTROY|작성자 바부

반응형
반응형
http://blog.naver.com/ohpowel/80023953224


#include <IOMANIP>

 

또는

 

#include <iomanip.h>

 

파일의 인클루두가 필요하다.

 

 

setw() 함수 ------------------------------------------------------------------

int a = 110;

cout << setw(4) << a << endl;

 

라고 한다면 44만큼의 공간을 확보해서 출력한다는 의미로 아래와 같다.

 

printf("%4d\n", a);

 

cout       //    printf

setw(4) --->  %4d

 

 

setprecision() 함수 ---------------------------------------------------------------

부동 소숫점 정밀도를  출력할 때 쓰는 함수이다.

 

double a = 1.15;

cout << setprecision(3) << a << endl;

 

라고 하면 정수부분 포함에서 총 3개가 출력된다. 1.15가 출력된다.

아래처럼 소숫점 이하 2개를 출력하는 구문과 동일하다.


printf("%.2f\n", a);







http://narusakura.tistory.com/196




 arg 앞에 & 붙이면 참조 - 같은 주소를 가지게 된다

포인터와 같다. 하지만 포인터는 포인터변수 4바이트를 차지하고 참조는 사용하지 않는다.

참조의 단점 : 초기화할 때 들어간 값은 변하지 않는다.

참조는 const 속성을 가진다. 변경불가! 


연산자오버로딩 ...대입연산자...

연산자오버로딩 기본코드


연산자오버로딩 main



(상속+연산자오버로딩)main



***************************************************************************************************************
진수표시
C++에서 cout에 어떠한 Data를 원하는 진수형식으로 표현하기 위해 oct(8진수), dec(10진수), hex(16진수) 등을 사용합니다.(이런것을 흔히 Manipulator이라고 합니다.)

#include <iostream.h>

main()
{

   int i;
   i = 12;

  cout << "12 -> 8진수 : " << oct << i << endl;
  cout << "12 -> 10진수 : " << dec << i << endl;
  cout << "12 -> 16진수 : " << hex << i << endl;

  return 0;
}



출력되는 Data에 일정한 간격을 표시하거나 소수출력시 자리수를 맞추기 위한 함수로 C++에는 setfill(), setw(), setprecision() 함수가 있습니다.(이 세개의 함수는 iomanip.h Header File에 정의되어 있습니다.)

setw()            공백 입력 함수
setfill()            빈공간 특정표시로 채우는 함수.
setpecision()   자리수를 맞추는 함수.
#include <iostream.h>
#include <iomanip.h>

main()
{

  double d;
  d = 12.345;

 
 cout << setw(15) << "hello!" << endl;
 cout << setw(15) << setfill('-') << "hello!" << endl;
 cout << setprecision(3) << d << endl;
 return 0;
}

 



cin,cout에서 많이 쓰이는 멤버함수들이란다~ 

width( int n ) : 문자 폭을 n으로 설정
precision( int n ) : 부동 수수점의 소수부분의 자리를 n으로 설정
put( char c ) : 문자 c를 출력
get( char c) : 문자 c에 입력(공백 포함). 파일의 끝에 거짓으로 반환. int형
write( char *p, int n ) : 버퍼 p의 바이트를 출력
read( char *p, int n ) : 버퍼 p의 바이트를 출력
eof() : 스트림의 끝에 참을 반환. int형
flush() : 스트림의 플러시 


반응형
반응형

http://cafe.naver.com/codingduckhoo/521




*LRESULT

: 4바이트 정수 형이다. WIN32환경에서 메시지를 처리한 후 O/S에게 신호를 주기 위해 사용한다.
  대부분의 경우 0을 리턴하면 메시지 처리가 완료되었으니 O/S에서 더 이상 처리할 메시지가 없다는 것을 의미하며,
  -1로 O/S가 처리하던 작업을 취소시키는 경우도 있다.

*HRESULT

: 32비트 정수형으로, 다양한 메시지를 리턴한다. 
  하위16byte까지 특정 오류 코드,
  상위 16byte까지 하위 16byte 코드 이외의 정보를 표현한다.

: 좀더 자세하게는 1.심각도 코드, 2. 기능 코드, 3.오류 코드의 세 가지 필드로 나뉜다.
  1.심각도 코드 - return 정보, 경고 또는 오류를 표시하는지 여부를 저장.
  2.기능 코드    - 오류를 담당하는 시스템 영역 식별, 예외를 표시하기 위해 할당되는 고유한 숫자.
  3.오류 코드    - 예외 처리를 위한 throw 정보.
  *예외를 throw할 때, 공용 언어 런타임은 HRESULT를 COM 클라이언트에 전달한다.
   비관리 코드가 오류를 반환하면,, HRESULT는 예외로 전환되고 공용 언어 런타임에 의해 throw된다(사용자 예외처리).

: 기본 특징은 TRUE와 FALSE의 값이 반대라는 점.
  TRUE = 0, FALSE = 1.
  상위 1byte로 TRUE / FALSE를 처리한다.

: 반환형이 HRESULT라고 해서 꼭 반환값을 가질 필요는 없다. 
  return값이 없어도 된다.

: 각종 코드를 저장하여 리턴하기 때문에 디버깅 처리시에 편리하다.
  대게의 경우, 반환값에 의한 예외처리시 if문을 이용하여 넘겨 받은 return값으로 오류 메시지를 띄우지만,
  HRESULT는 예외상황을 스스로 인식하여 코드화 하기 때문에 사용자는 O / S에서 throw한 에러코드 처리만 한다.
  비관리 코드가 오류를 반환한 것이 아니고, 
  특정한 예외 처리를 할 것이 아니라면, 어떤 예외 사항이 발생했는지 사용자가 따로 throw할 필요가 없다는 것.

: HRESULT가 반환하는 값은 다음과 같다.
  (반환값이 수십 개에 달하여, 요약한다. 자세한 내용은 MSDN의 HRESULT Values를 참조)

 S_OK(Operation successful(0x00000000))
  : 때때로 Boolean TRUE 값(0x0)으로 S_FAUL와 함께 사용되며 함수가 성공하였음을 의미

  E_ABORT(Operation aborted(0x80004004))
  : 작동 정지

  E_ACCESSDENIED(General access denied error(0x80070005))
  : 일반적 접근의 금지된 에러

  E_FAIL(Unspecified failure(0x80004005))
  : 실행 실패

  E_HANDLE(Handle that is not valid(0x80070006))
  : 적합하지 않은 처리

  E_INVALIDARG(One or more arguments are not valid(0x80070057))
  : 하나 혹은 그 이상의 인자가 불분명

  E_NOINTERFACE(No such interface supported(0x80004002))
  : 요청한 인터페이스를 미지원

  E_NOTIMPL(Not implemented(0x80004001))
  : 멤버 함수에 구현 코드가 미포함

  E_OUTOFMEMORY(Failed to allocate necessary memory(0x8007000E))
  : 필요한 메모리가 할당할 수 없음

  E_POINTER(Pointer that is not valid(0x80004003))
  : 적합하지 않은 포인터

  E_UNEXPECTED(Unexpected failure(0x8000FFFF))
  : 치명적인 실패를 의미

반응형
반응형

BLOG main image




BOOL CtestApp::InitInstance()

{

m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED); //창 최대화에 대한 함수를 추가해주면 된다

m_pMainWnd->UpdateWindow();


}

반응형
반응형


 xcopy  非Java 

2012/02/25 12:15

복사http://blog.naver.com/kisself79/50135049912


xcopy copyFromDir copyToDir /S /I /E /Y


xcopy  /옵션  [원본]  [복사본]
 
※[원본]과 [복사본]은 위치를 포함
 
ex)XCOPY /R /Y /S /Z /Q \\127.0.0.1\C$ \\localhost\D$
 
xcopy 옵션
/C : Continue-복사 시 오류가 발생하더라도 계속적으로 명령을 수행. 주로 미디어가 손상되어 복사 실패가 일어나는 겨우 사용하면 좋은 옵션.
/Q : Quiet-파일 복사 시에 기본적으로 복사되는 파일 목록을 출력하는 것이 기본이지만, 이 옵션으로써 파일목록을 출력하지 않음. 미약하게 빠른 복사 작업이 이루어짐.
/L : 복사하진 않고 복사할 리스트만 출력.
/Z : 숨김 속성을 가진 파일들 또한 포함해서 복사하라는 옵션.
/R : 읽기 전용 파일을 복사.
/Y : 이미 파일이 있을 때 덮어쓰겠냐는 메시지를 출력하지 않음.
/N : NTFS에 있는 데이터의 긴 이름의 파일명을 단축시켜 FAT파일 시스템으로 복사함.
/S : Sub Directory. 하위 디렉토리의 내용도 포함해서 복사.
/E : Empty. 디렉토리가 비어있으면 제외하라는 명령어.
/W : Wait. 준비까지 마치고 아무키나 누르면 그때부터 복사 시작.
/D : 드라이브에 동일한 파일이 존재하는 경우, c: 드라이브의 파일이 최신 것일 경우만 덮어쓰기를 한다. /D:06-07-2006 식으로 사용하여 특정한 날짜 이후의 파일들만 복사할 수도 있음
※/D 옵션은 업데이트 스크립트 등 제작 시 유용함


출처
http://m.blog.naver.com/PostView.nhn?blogId=tmd794613&logNo=60134745236&scrapedType=1&scrapedLog=50135049672

[출처] xcopy|작성자 도쿄네코


반응형
반응형

http://blog.naver.com/xogml_blog/130144674709


인라인 함수란 무엇인가 ? 

우선 일반 함수를 알아보면, 일반 함수는 우선 매개변수를 스택에 집어넣고, 함수를 호출한다. 다시말하면


//int x86     *.cpp

int add(int a, int b) { return a + b; } 이러한 코드는

int main(void) {

add(1, 2);

return 0;

}


//int x86     *.asm

push 2

push 1

call ?add@@YAHHH@Z ; add1

add esp, 8

mov DWORD PTR _n1$[ebp], eax

이런식으로 호출된다.

또한 여기에는 적지않았지만 리턴값을 위한 스택 push, pop도 있고 라턴후 스택정리를 위한 pop도 있다..

이러한 함수 호출은 스택에 접근 하기 떄문에, 다시말하면 메모리에 접근하기 때문에 속도 저하가 생길수 있다.

이러한 스택접근, 즉 메모리 접근을 피하는 방법은 무엇이 있을까? 에서 나온 한편의 해결책이 인라인 함수이다.

위의 내용을 자세히 보려면 [calling convention] 을 보면 된다.



원리 ?

기계어를 통채로 치환한다. 즉 함수 호출없이 코드를 가져다 붙인다. ㅋ 그래서 스택접근이 없기 떄문에 메모리 접근이

없고 결국 속도면에서 이득을 얻을수 있다.



사용 ?

inline returnType functionName(argument) {

//routine...

}


ex)


//main.cpp

inline int add(int a, int b) {

return a + b;

}


int main(void) {

add(1, 2);

return 0;

}

이런식으로 사용하면 된다. 이와같이 인라인 함수를 사용해서 컴파일 하게 되면


//main.cpp

mov eax, 1

add eax, 2

mov DWORD PTR _n2$[ebp], eax

어셈 코드가 위와같이 나오게 된다. 즉 push, pop가 없으므로 성능에 향상이 있다.



문제점 1. 코드의 길이가 길어진다 ?

직관적으로 보면 메서드의 기계어를 통채로 때어다가 붙이기 때문에, 목적코드가 길어질수 있다....

라고 Effective C++이라는 책에 나오고 있지만, 오히려 목적코드를 작게 해줄수도 있다고 적혀잇다. 비교해보자

a) 일반 함수를 사용할경우 : 매개변수 push + 복귀주소 eip push + 함수호출 call

b) 인라인 함수 사용할경우 : 함수의 목적코드가 통째로 와서 붙음.


정리하면 함수의 크기가 "매개변수 push + 복귀주소 eip push + 함수호출 call" 보다 클경우 목적 코드의 길이가 길어지고

작을경우에는 오히려 목적 코드의 길이가 작아진다.


따라서 함수가 복잡할경우에는 인라인 함수의 사용을 줄여야 한다. 하지만 단순한 함수일경우 무조건 인라인이다.



문제점 2. 디버깅이 어렵다.

당연한 이야기이다. 함수 모듈화의 장점은 재활용성과 더불어 코드 가독성에 있다. 하지만 call-return 구조를 포기하되 성능을

택하였으므로 코드가 보기 어려워지고 결과적으로 디버깅이 어렵게 된다.


더불어 vs에서는 최적화 옵션때문에 release 일때만 인라인으로 처리하고(어셈을 만들고), debug 모드일경우에는 일반 함수로 처리. 



문제점 3. inline 함수는 Internal Linkage 이다.

다시말해 인라인 함수는 내부연결이다. 더 나가기전에 internal linkage에 대해 알아보면


a. Internal Linkage 

- 영역의 심볼(전역변수, 함수)이 자신을 선언한 컴파일 단위(파일)에서만 사용 가능.

-> static 전역변수, inline 함수, function template, 매크로

-> C++ 문법의 const 


b. External Linkage

- 영역의 심볼이 프로젝트 내의 모든 컴파일 단위에서 사용 가능

-> 일반 전역변수, 일반 함수

-> C 문법의 const

※ 단 C++문법의 const도 C의 const처럼 External Linkage로 쓸수 있다는 밥법이 있다.



즉 inline 함수는 내부 연결의 속성을 갖기 때문에 이런것이 불가능 하다.


//add.cpp

inline int add(int a, int b) {

return a + b;

}


//main.cpp

inline int add(int a, int b);


int main(void) {

add(1, 2);

return 0;

}

다시말해 add.cpp 에서 작성한 인라인 add함수는 자신의 컴파일 단위, 다시말해 add.cpp에서만 효력한다. 그렇다면 어떻게 해야 할까?

해법은 헤더파일, 즉 헤더파일에 인라인 함수의 선언과 구현을 다 해주고 여러 파일들에서 이 헤더를 추가하여 사용하면 된다.



문제점 4. 인라인 함수를 함수포인터로 사용 ?

볼것도 없이 우선 해보자


//main.cpp

inline int add(int a, int b) {

return a + b;

}


int main(void) {

int (*pAdd)(int, int) = &add;

pAdd(1, 2);

return 0;

}

이 코드의 목적코드를 보자. 과연 함수포인터르 받은 인라인 함수가 사용 되었을까 ? 


; 5    : int main(void) {


push ebp

mov ebp, esp

push ecx


; 6    :  int(*pAdd)(int, int) = &add;


mov DWORD PTR _pAdd$[ebp], OFFSET ?add@@YAHHH@Z ; add


; 7    :  pAdd(1, 2);


push 2

push 1

call DWORD PTR _pAdd$[ebp]

add esp, 8


; 8    :  return 0;

어 사용 안됬다. 다시말해서 인라인 함수를 함수포인터로 받을수는 있지만, 함수 포인터로 사용하면 일반 함수처럼 사용된다.

뭔상관이야 ? 할수도 있는데 이런 경우를 생각해보자.

누구나 c언어를 배울때 stdlib의 퀵소트를 사용해본적이 있을것이다. 


void qsort(void * base, size_t num, size_t size, int(* comparator)(const void *, const void *));

여기서 세번째 함수로 넘겨주는것이 함수포인터이다. C언어에서 

1. 변하지 않은 전체 알고리즘과, 변해야 하는 정책을 분리하는 것이 좋다.

2. C에서는 변하는 것을 함수 인자화, 즉 함수 포인터로 표현하면 된다.


퀵소트의 알고리즘을 보면 선택된 인자 두개를 비교하는 루틴이 있다는것을 알것이다. 이 루틴에 따라서 오름차순, 내림차순이

결정되는데, 즉 무지막지하게 저 comparator가 호출되는것이다.


간혹가다 "아 이 comparator가 많이 호출되고 단순한 함수니까 inline으로 만들자" 라는 사람이 있을텐데...

이쯤되면 눈치 챘을것이다. 함수포인터는 inline으로 사용될수 없다.


그럼 해결책은 ? 아쉽게도 C언어 에서는 없다....

단 C++에서는 함수객체라는 이름으로 해결방안이 있다. 

반응형
반응형

http://bravedog.blog.me/100005576789

프로그램 개발환경이 WIN32로 바뀌면서 의미를 잃어버린 포인터들이 있다. 이것이 near 및 far포인터이다. 하지만 예전의 소스를 해석하다 보면 심심찮게 볼 수 있다. 예전의 16비트 OS들은 메모리를 세그먼트(16bit):옵셋(16bit)의 형태로 다루었다. 옵셋을 사용하여 접근할 수 있는 메모리 공간은 64KB가 되고 세그먼트와 옵셋을 모두 사용할 경우 접근할 수 있는 메모리 공간은 총 1MB가 된다.

 

터보 C에서는 디폴트로 스몰모델(small model)의 컴파일을 사용한다. 이것은 옵셋만의 변화로 메모리에 접근하는 방식으로써 앞서 말한 바와 같이 64KB의 메모리 공간에 할당이 된다. 하지만 필요에 따라서 더 많은 메모리가 필요할 경우 터보 C에서는 near와 far키워드를 사용하여 접근할 수 있다.

 

near 포인터는 64KB용, far 포인터는 1MB용으로 스몰모델에서는 데이터의 기본형을 모두 near형으로 가정하기 때문에 near는 쓰지 않아도 된다.

 

int far *fp;              // fp는 1MB 메모리 영역용 far 포인터

int near *np;          // np는 64KB 메모리 영역용 near 포인터

 

단, far 형 포인터에 메모리번지를 대입할 때는 long형 정수를 사용해야 한다. long형 정수(4바이트)중 앞의 2바이트는 세그먼트를, 뒤쪽의 2바이트는 옵셋을 나타낸다.

 

np=0x1234;             // np 옵셋(0x1234)

fp=0x20001234L;      // fp는 세그먼트(0x2000):옵셋(0x1234)

 

뒤에 설명할 동적 메모리에 관한 함수들은 모두 far 포인터 형 함수를 별도로 가지고 있다. far 포인터 형 함수는 unix와 ansi c에서는 제공이 되지 않고 도스와 윈도우에서만 사용하였지만 최근에는 WIN32로 환경이 바뀌면서 사용하지 않게 되었다. 좀더 상세히 말하면 near포인터와 far포인터는 windef.h파일에 정의되는데 win32로 바뀌면서 빈 문장열로 처리하도록 변경되었다.

 

참고로 기존의 16비트 OS환경에서의 메모리 관련 far 포인터 형 함수의 원형들은 다음과 같다.

 

near 형far 형
mallocvoid far *farmalloc(unsigned long nbytes);
callocvoid far *farcalloc(unsigned long nunits, unsigned long nunitz);
reallocvoid far *farrealloc(void far *oldblock, unsigned long nbytes);
freevoid far *farfree(void far *block);
memsetvoid far *far_fmemset(void far *s, int c, size_t n);


http://goo.gl/PJqZm


far 포인터(far *)인 경우에는 L로 시작합니다 - LPVOID





반응형
반응형


CEGUI 사용시 GUI를 제외한 렌더링화면이 나오지 않거나 이상하게 렌더링될때  CEGUI

2009/06/14 20:16

복사http://blog.naver.com/woocom2/90048906712


CEGUI를 내가 사용하는 프레임워크에 붙여봤다.
그런데 이상한 현상하게도 GUI를 제외한 메쉬나 오브젝트들이 렌더되지 않았다.
처음시작에 잠깐 1프레임 보이다 사라진다.

포럼과 CEGUI카페를 찾아봤지만 겨우겨우 포럼에서 방법을 찾았다.
CEGUI가 디바이스를 가지고 RenderState를 변경하는 듯했다.
그래서 CEGUI가 렌더되고 나서는 RenderState를 복구해주지 않을 경우 렌더화면이 외곡되거나 나타나지 않는 것이다.
이것을 해결하기 위해서는 
IDirect3DStateBlock9* 인터페이스를 사용해서 RenderState를 저장했다가 매 프레임마다 복구시켜주는 과정이 필요하다.

사용법은 이렇다.
//...
 IDirect3DStateBlock9*            m_OriRenderState;        
//...

// 렌더링 세팅이 끝난후
device->CreateStateBlock(D3DSBT_ALL, &m_OriRenderState);

// 렌더링
if( SUCCEEDED( device->BeginScene() ) )
{
        m_OriRenderState->Apply();           // CEGUIDirectX9렌더러가 RenderState를 변경시키므로 원래 랜더상태 복원
        DrawScene();                               // 카메라 위치와 캐릭터, 임의로 생성된 박스를 그린다.        
        CEGUI::System::getSingleton().renderGUI();
        pTextOut->DrawText(fpsText);        // 프레임을 나타낸다.        
        device->EndScene();
        device->Present(0,0,0,0);
}

반응형
반응형

CEGUI - 2005에서 한글폰트 출력하기


2007.10.18 01:10

폰트가 정말 깔끔하게 나온다. 맘에 들어 꺄악.

CEGUI포럼을 검색하다 보니 중국어 출력 관련 질문이 있었는데 그 부분을 참고 했다.

원문 : http://www.cegui.org.uk/phpBB2/viewtopic.php?t=2503&highlight=language

 

1. 한글폰트를 포함하는 .font를 만들고 그것을 FontManager로 로드합니다.

폰트 정보를 로드한 후 폰트의 이름을 기본 폰트로 설정해 줍니다. 여기에서 한 가지 팁은 CEGUI에서 한글 폰트를 사용하면 폰트를 비트맵으로 변환하여 읽어들인다는 것입니다. 비트맵으로 변환하는 과정에서 폰트의 사이즈가 크거나, 한자를 포함하여 폰트자체의 용량이 크게되면 안된다는 것입니다. 한자를 포함하는 폰트를 사용하게 되면 폰트를 비트맵으로 변환하는 과정에서 데드락이 걸린다고 하는군요. 실질적으로 소스를 살펴보겠습니다.

- .font

<?xml version="1.0"?>

<Font Name="Tahoma-12" Filename="HMKMAMI.TTF" Type="FreeType" Size="24" NativeHorzRes="1024" NativeVertRes="768" AutoScaled="true" AntiAlias="true"/>


- .cpp

CEGUI::FontManager::getSingleton().createFont ("Tahoma-12.font");
CEGUI::System &sys = CEGUI::System::getSingleton();
sys.setDefaultFont((CEGUI::utf8*)"Tahoma-12");

 

2. 소스를 살펴보면 출력할 폰트를 UTF8로 변환하는 코드를 볼 수 있다.

 std::wstring szWstring(L"노바 - Nest Of Valuable Academy");
 char *szUtf8String = NULL; 
 int iLengthAnsiString = 0; 
 iLengthAnsiString = WideCharToMultiByte(CP_UTF8, 0,szWstring.c_str(), szWstring.capacity(), NULL, 0, NULL, NULL); 
 szUtf8String = new char[ iLengthAnsiString]; 
 memset(szUtf8String, 0, sizeof(char)*(iLengthAnsiString)); 
 WideCharToMultiByte(CP_UTF8, 0,szWstring.c_str(), szWstring.length(), szUtf8String, iLengthAnsiString, NULL, NULL); 
 wnd->setText((CEGUI::utf8*)szUtf8String);
 delete [] szUtf8String; 
 szUtf8String = NULL;

위의 코드처럼 unicode -> UTF8로 변환하는 작업을 거쳐야 한글 출력이 가능합니다.

 

3. 2007년 10월 19일 추가작성

위의 코드는 수 많은 UI를 코드에 단다고 했을 때 범용성이라고는 누꼽만큼도 없는 코드입니다. 단지 한글 출력이 가능하다라는 정도의 소스가 되겠습니다. 그래서 필요한 것은 시스템인코딩된 멀티바이트를 UTF8로 인코딩을 시키는 코드를 작성해야 합니다. 그런데! (시스템인코딩)멀티바이트 -> (UTF8)멀티바이트로 변환을 시키는 함수가 없기 때문에 멀티바이트->유니코드->멀티바이트로 변환 과정을 거쳐 UTF8로 변환 시켜야 합니다.

이번 작업으로 한글변환에 대한 기본지식은 어느정도 생긴것 같습니다. widechar가 유니코드. multybyte가 완성형 그러니깐 일반적인 char형 변수. UTF8은 char형이나 UTF8인코딩 변환 과정을 거친다는 것입니다.

멀티바이트 문자열의 길이는 strlen()함수를 통해 알 수 있고 유니코드는 lstrlen()함수를 통해 알 수 있습니다. 하루 동안 삽질 하면서 정말 많은 문서를 봤지만 기억에 남는건..그닥없습니다.ㅎ

그냥 두서 없이 함수 구현부만 적어 놓겠습니다.

 

char* CEGUIApplication::ANSI_TO_UTF8(char *szANSI) 

    int nLen = MultiByteToWideChar(CP_ACP, 0, szANSI, -1, NULL, NULL); 
    LPWSTR lpwsz = new WCHAR[nLen]; 
    MultiByteToWideChar(CP_ACP, 0, szANSI, -1, lpwsz, nLen); 
    int nLen1 = WideCharToMultiByte(CP_UTF8, 0, lpwsz, nLen, NULL, NULL, NULL, NULL); 
    LPSTR lpsz = new CHAR[nLen1]; 
    WideCharToMultiByte(CP_UTF8, 0, lpwsz, nLen, lpsz, nLen1, NULL, NULL); 
    delete []lpwsz; 
    return lpsz; 
}

이런식으로 해 놓고!

CEGUI에서의 사용은 아래와 같이 하면 되겠습니다.

 

wnd->setText((CEGUI::utf8*)ANSI_TO_UTF8("윤경옥-NOVA"));

궂이 UTF8로 변환을 시켜주는 이유는 CEGUI::String형이 UTF8로 인코딩 되어 있기 때문입니다.

2003버젼에서는 이런 변환 과정이 필요없지만 2005는 프로그램의 버그로 보이는 문제 때문에 UTF8로 인코딩을 해도 한글 출력이 잘 되지 않는다고 하는군요. 이런 공개용 라이브러리를 공부 하는데 가장 좋은 방법은 외국 사이트의 포럼을 통해서가 가장 효과적인 것 같습니다.

 

짧은 프로그래머 생활 이었지만 코딩을 할 때마다 뼈저리게 느끼는건 하늘 아래 새로운 것이 없다는 말 처럼 내가 지금 겪고 있는 문제를 과거에 누군가는 반드시 겪었었고, 앞으로도 반드시 겪게 될거라는 것입니다. 이런 논리속에서 프로그래머에게 필요한 기술의 하나가 정보수집 능력에 있는것 같습니다.




  • 2007/10/30 17:18답글

    신고

    전 똑같이 해봐도 안되네요..;;온리 영어만 출력되구ㅡ,ㅡ; 
    ANSI_TO_UTF8함수랑 밑에 settext 만 추가해주면 출력이 되는건가요?
    폰트는 tohoma 쓰고있어요.
    디버깅을 해보니 마지막 return lpsz변수에 한글이 무참히 깨져있네요..;;영문은 살아있고

  • 2007/10/30 22:45답글

    신고

    일단 소스를 살펴보면 .font파일을 로딩한걸 보실 수 있을겁니다.
    그 파일을 열어보면 xml로 구성하려는 폰트와 폰트의 사이즈 정보가 들어가 있습니다.
    여기에 한글출력이 가능한 폰트를 입력해줘야 됩니다.
    위에 작성한 타호마폰트는 .font에 폰트 정보를 임의적으로 준 이름이거나 시스템폰트입니다.
    추가적으로 CEGUI에서 사용하는 폰트는 실시간 해당 한글폰트의 텍스쳐를 생성해서 출력해주는 방식입니다. 이는 컴파일과정에서 일어납니다.

  • 2007/12/11 19:44답글

    신고

    멀티바이트를 유니코드로 바꾸고 유니코드를 UTF8로 바꾸는것은 
    inline
    std::wstring convMbcs2Uni(const std::string &mstr)
    {
    USES_CONVERSION;
    std::wstring wstr(A2W(mstr.c_str()));
    return wstr;
    }
    inline
    std::string convUni2Utf8(const std::wstring &wstr)
    {
    USES_UTF8_CONVERSION;
    std::string ustr(W2A(wstr.c_str()));
    return ustr;
    }
    #define CONV_MBCS_UTF8(a) convUni2Utf8(convMbcs2Uni(a)).c_str()
    이런식으로 할수도 있더군요

반응형
반응형

CEGUI 그냥 사용하기엔 정말 무겁습니다.|CEGUI분석
전체공개2008.03.30 00:07

현재 버젼이 어느 정도 안정화 단계에 접어 들었기 때문에 추후 버젼업 시에 관련 부분 패치를 포기하시고,

라이브러리 자체를 뜯어 고치셔야 상용게임 수준에서는 필요하다고 봅니다.

 

1. freetype라이브러리의 실시간 비트맵폰트 생성 부분.

내부 캐싱은 지원하질 않습니다. 특정 비트맵폰트가 필요하면 그 폰트의 페이지에 있는 모든 폰트를 그려넣은 텍스쳐를 생성합니다. 정확히 유니코드의 완성형 코드 구성이 어떻게 이뤄졌는지는 모르겠으나 "가"라는 글자를 치면.."가 갸 거 겨"와 같은 앞 뒤에 있을 수 있는 글자가 포함된 텍스쳐를 생성한다는 겁니다. 이는 소스상에서 수정할 수 있습니다. 어떤거였는지 생각은 나질 않으나 CEGUIText? 클래스의 선언부에 이 텍스쳐 안에 포함될 글자의 숫자를 define해놓은게 있습니다. 아마 256 정도로 define을 해놨는데 확실히 그 보다 작은 수로 하면 텍스쳐 생성 및 write시간이 적게 걸립니다. 장단점은 있겠죠? 텍스쳐를 크게 만들고 연관글자의 입력시 텍스쳐 생성에 대한 시간이 없을 수 있다는 겁니다. 이러한 부분은 비트맵폰트 텍스쳐의 캐싱코드를 포함해서 만들어야 될 거란 생각이 듭니다.

 

2. 지나친 update()함수의 호출.

UI라이브러리는 업데이트 함수의 호출을 통해 메모리버퍼의 내용과 프로퍼티 설정 내용을 동일시 시켜줍니다. CEGUI의 업데이트는 너무 무겁고, 너무 자주 호출됩니다. 특정 프로퍼티 설정이 변경이 되면 바로 업데이트 함수를 호출해주면서 버퍼의 내용과 프로퍼티를 동일 시 시켜주는데 그럴 필요 없다는 겁니다. 렌더링 전에 한 번만 호출해 주면 된다는 겁니다.

 

3. CEGUI::String클래스.

요 놈은 std::string클래스를 랩핑해서 만든 클래스 입니다. 맵 저장 시 정렬 순서에 대한 오퍼레이터와 몇 가지 차이점이 있으나 큰 차이는 보이질 않습니다. 그런데!!!! 디버깅 시에 String객체의 내용을 조사식 창에서 확인할 수 없습니다. 팁이라면 std::string과 CEGUI::String클래스간의 변환은 c_str()매서드를 통해 이루어질 수 있습니다. 이 클래스에 대한 중요한 얘기를 할게 있었는데 잠깐 다른 생각 하는세 까먹었습니다.

 

4. UTF-8 인코딩

이 놈 역시 상당히 거슬립니다. CEGUI에 들어가는 문자열은 모두 UTF-8로 인코딩을 시켜야합니다. 멀티바이트와 유니코드는 알겠는데UTF-8? 음 저 역시 깊게 설명 드릴 수는 없고 UTF-32인코딩 방식이 일반적으로 쓰이는 방식이기 때문에 UTF-8인코딩 형식의 문자열로 바꿀려면 멀티바이트 설정의 솔루션에서는 멀티바이트(UTF-32)를 유니코드로 변환 하고 이걸 다시 멀티바이트(UTF-8)로 변환을 거쳐야 합니다. 변환 관련 Flag중에 인코딩 형식을 설정해주는게 있습니다.

 

5. 지나친 Render()함수의 호출.

Update()함수와는 또 다른 개념입니다. 프레임윈도우에 CEGUIStaticImage를 3개를 attach시킨 캐릭터 상태표시창이 있었는데 이거 하나 그릴 때 Render()함수가 27번이 호출이 됐습니다. 사각형 이미지의 경우(물론 룩앤필 설정에서 이를 최소화 시킬 수 있습니다. staticimage의 looknfeel설정을 각 테두리 이미지는 하나도 없에고 배경만 남기는 겁니다.)Left-Top, Left-Middle, Left-Bottom과 같이 각 각을 9번 렌더링 합니다. 이걸 최적화 시키기 위해서는 CEGUITexure클래스의 연관관계를 파악 후에 Update()함수에 의해 최종적으로 완성된 버퍼를 하나의 텍스쳐에 옮겨담고 한 번만 렌더링 하는 겁니다.

 

6. 수 많은 예외처리

예외처리는 때론 유용하지만 때론 불편합니다.

 

 

제가 사용하면서 느낀 건 이 정도의 이유라 상용게임에서 사용하기엔 무리가 있다는겁니다.

이 작성자의 게시글|더보기
http://acasia.na.mu
http:://actionslove.tistory.com ..
덧글 4개||조회수 916
  • 2008/03/30 20:37답글

    신고

    오~ 그렇군요.. 시간 절약이 많이 되는 정보네요
    감사합니다 ^^

  • 2008/04/30 17:01답글

    신고

    연구하신 내용을 이렇게 보기좋게 올려주셔서 정말 감사드립니다.
    지금 회사 프로젝트 진행하면서 CEGUI 로 ui 구현하려고 하는데, 이글을 보고 많이 고민이 됩니다.
    현재는 CustomUI 를 개조해서 쓰고 있는데요 ... CEGUI 퍼포먼스 문제가 제일 고민이네요 ㅡㅡ;;;

  • 2008/07/22 11:55답글

    신고

    1번에 내부 캐싱이 무슨 뜻인지 잘 모르겠습니다. 구체적으로 설명해줄 수 있나요?

  • 2008/07/22 12:50답글

    신고

    사용하지 않는 텍스쳐와 사용하는 텍스쳐를 구분하여 적절한 타이밍에 메모리에서 해제를 하는 것과 같은 일을 캐싱이라는 단어로 표현했습니다. CEGUI라이브러리 내부적으로 이러한 글자 텍스쳐에 대한 캐싱을 하지 않기 때문에 프레임워크의 업데이트 타임에 레퍼런스 카운트를 체크해서 메모리를 해제 해주는 부분을 구현할 필요가 있을 듯 합니다. 내부적으로는 조합형 폰트를 출력할 때 해당 폰트의 앞 뒤 몇개를 동시에 만듭니다. 이렇게 만들어진 텍스쳐를 맵에서 관리를 하구요. 텍스쳐맵에 대한 해제 시점을 CEGUI::System을 해제 할 때 함께 메모리에서 삭제 됩니다.

반응형
반응형

http://juree.tistory.com/980



GPG Study에서 퍼온글입니다. 
CEGUI에서 한글 구현하려고 고생하고있는데. 글 올려주셔서 감사합니다.


전에 CEGUI에 대해 정리해둔게 있어서 옮깁니다. 
먼저 CEGUI는 www.cegui.org.uk 에서 받을 수 있습니다. 
이곳에서 
cegui_mk2-0.4.0(<-최신버전 드래그 앤 드롭구현)
cegui_mk-0.4.0-deps-common(안에 dependencies 와 Samples를 같은 디렉토리 안데 넣습니다.) 
cegui_mk-0.4.0-deps-vc71-xerces(역시 안에 dependencies 와 Samples를 같은 디렉토리 안데 넣습니다.) 
이 세 파일을 받으신후에 (root:cegui_mk2makefileswin32VC++7.1) 안에 있는 프로젝트 파일을 열어 빌드를 합니다. 
빌 드한후에 (root:cegui_mk2lib)안에 여러가지 lib화일이 만들어져 있을겁니다. 이들중 CEGUIBase.lib가 가장 중요한 lib입니다. 이 파일을 라이브러리 경로에 포함하시고 실행파일 안에 있는 CEGUIBase.dll, devil.dll, ilu.dll등등의 파일을 자신의 어플리케이션으로 옴기면 준비는 다 된것입니다.(이후 자신의 어플리케이션을 빌드할때 CEGUI헤더파일과 lib포함) 

다음 자신의 그래픽엔진에 맞는 XXXCEGUIRederer와 XXXTexture를 만들면 됩니다. 이는 안에 순수 가상클래스로 만들어진 renderer와 Texture를 상속받고 인터페이스 대로 구현만 하면 됩니다. 이렇게 하면 XXXCEGUIRenderer.lib, XXXCEGUIRenderer.dll 이 만들어 지고 자신의 어플리케이션에CEGUIBase.lib, XXXCEGUIRenderer.lib를 포함하면 됩니다. 

이후 한글을 사용하기 위해서는 font파일을 만들어야 합니다. 이파일을 열어서 


< ?xml version="1.0" ? > 
< Font Name="Tahoma-12" Filename="NGULIM.ttf" Type="Dynamic" Size="12" NativeHorzRes="800" NativeVertRes="600" AutoScaled="true" > 
< GlyphRange StartCodepoint= "44032" EndCodepoint= "55203" / > 
< GlyphSet Glyphs="上下" / > 
< /Font >


이 안에 이미지폰트나 트루타입폰트 설정을 해주면은 됩니다. 여기서 중요한것만 설명하면 Filename은 폰트 이름 전 새굴림(NGULIM.ttf)을 사용했습니다. type 폰트종류 Dynamic은 투루타입 Static은 이미지폰트, 이 폰트에서 한글을 사용하기 위해서는 Glyph명령을 사용해서 폰트내에서 사용할 문자코드를 정해줘야 합니다. 
위에서 GlyphRange 문자코드(10진수)의 시작과 끝을 정해주는 겁니다. 위에서 44032는 폰트내에서 "가"에 해당하는 문자코드이고 55203은 한글문자코드의 마지막코드입니다. 이 외에도 특수 문자나 한자등의 사용을 위해 개별적으로 입력시 GlyphSet Glyphs = " " <--여기에 원하는 문자를 넣어 주면 됩니다. 

그리고 나서 자신의 코드에서 button->setText((CEGUI::utf8*)"미션1"); 이런식으로 사용하면 됩니다.그러고 나서 저장할때 파일->저장 고급 옵션 에서 유니코드로 저장하시면 됩니다. 이상이 한글 출력부분이고.. 

한글 입력시에는 CEGUI는 기본적으로 GUI만 구현되어 있습니다. Ogre, irricht, 그곳예제에서도 한글입력에 대해서는 찾을 수 없습니다. 위에 열거한 것들의 입력부분이 한글이나 비영미권의 언어를 지워하지 않습니다. 그래서 입력부분은 따로 구현해 줘야 합니다. 한/영 키를 인식해서 키보드에서 들어오는 신호를 해당 문자코드로 변환해주는 부분은 자신이 직접 구현해야 합니다. 

이상입니다. 그외 세부적인 부분 Scheme, layout 다중폰트 사용등은 레퍼런스문에다 잘 나와있습니다.
--위의 내용보고 구현한 예제입니다.

반응형
반응형


http://iq_up.blog.me/100125952192 

 

 

 

 

 

VC++ 에서

AfxMessageBox 및
MessageBox 사용 예

C:\Program Files\Microsoft Visual Studio\VC98>findstr /c:"MB_ICON" /s *.h
Include\MSI.H://  A message box icon type:  MB_ICON*, where no icon is the default
Include\MSIQUERY.H:// MB_ICONERROR, MB_ICONQUESTION, MB_ICONWARNING, MB_ICONINFORMATION
Include\WINUSER.H:#define MB_ICONHAND                 0x00000010L
Include\WINUSER.H:#define MB_ICONQUESTION             0x00000020L
Include\WINUSER.H:#define MB_ICONEXCLAMATION          0x00000030L
Include\WINUSER.H:#define MB_ICONASTERISK             0x00000040L
Include\WINUSER.H:#define MB_ICONWARNING              MB_ICONEXCLAMATION
Include\WINUSER.H:#define MB_ICONERROR                MB_ICONHAND
Include\WINUSER.H:#define MB_ICONINFORMATION          MB_ICONASTERISK
Include\WINUSER.H:#define MB_ICONSTOP                 MB_ICONHAND
Include\WINUSER.H:#define MB_ICONMASK                 0x000000F0L


Include\MSIQUERY.H://MB_OK,MB_OKCANCEL,MB_ABORTRETRYIGNORE,MB_YESNOCANCEL,MB_YESNO,MB_RETRYCANCEL
Include\MSIQUERY.H:// Returns Win32 button codes: IDOK IDCANCEL IDABORT IDRETRY IDIGNORE IDYES IDNO


MessageBox(hDlg,"message","title",MB_ICONWARNING|MB_YESNO);
이렇게 할 수 도 있고.

MessageBox(0,"desktop message","title",MB_ICONWARNING|MB_YESNO);
MessageBox(hDlg,"message","title",MB_ICONWARNING|MB_OK);

::AfxMessageBox("AfxMessageBox(\"메시지\")");
::AfxMessageBox("MB_ICONHAND",MB_ICONHAND);
::AfxMessageBox("MB_ICONQUESTION",MB_ICONQUESTION);
::AfxMessageBox("MB_ICONEXCLAMATION",MB_ICONEXCLAMATION);
::AfxMessageBox("MB_ICONASTERISK",MB_ICONASTERISK);
::AfxMessageBox("MB_ICONWARNING",MB_ICONWARNING);
::AfxMessageBox("MB_ICONERROR",MB_ICONERROR);
::AfxMessageBox("MB_ICONINFORMATION",MB_ICONINFORMATION);
::AfxMessageBox("MB_ICONSTOP",MB_ICONSTOP);
::AfxMessageBox("MB_ICONMASK",MB_ICONMASK);
::AfxMessageBox("MB_ICONMASK | MB_ABORTRETRYIGNORE",MB_ICONMASK | MB_ABORTRETRYIGNORE);//
::AfxMessageBox("MB_DEFBUTTON3 는 3번째 버튼을 디폴트로 활성화 합니다.(1~3)",MB_ICONMASK | MB_ABORTRETRYIGNORE|MB_DEFBUTTON3);//


::AfxMessageBox("AfxMessageBox(\"메시지\")");

유의: 아이콘에 대한 정의가 없으면 기본적으로 경고느낌표이다.

아래의 알림느낌표와 경고느낌표의 아이콘이 다름에도 유의하자.

- 정의하지 않거나,MB_ICONWARNING,MB_ICONEXCLAMINATION 이거나 3가지 경우이다.

 

::AfxMessageBox("MB_ICONHAND",MB_ICONHAND);


::AfxMessageBox("MB_ICONQUESTION",MB_ICONQUESTION);


::AfxMessageBox("MB_ICONEXCLAMATION",MB_ICONEXCLAMATION);



::AfxMessageBox("MB_ICONASTERISK",MB_ICONASTERISK);
알림 느낌표이다.

위의 경고느낌표와는 느낌이 조금 다르다.

Asterisk 는 별표이다. information으로 해도 된다.


::AfxMessageBox("MB_ICONWARNING",MB_ICONWARNING);

                                                         



::AfxMessageBox("MB_ICONERROR",MB_ICONERROR);



::AfxMessageBox("MB_ICONINFORMATION",MB_ICONINFORMATION);




::AfxMessageBox("MB_ICONSTOP",MB_ICONSTOP);

 



::AfxMessageBox("MB_ICONMASK",MB_ICONMASK);




::AfxMessageBox("MB_ICONMASK | MB_ABORTRETRYIGNORE",MB_ICONMASK | MB_ABORTRETRYIGNORE);


::AfxMessageBox("MB_DEFBUTTON3 는 3번째 버튼을 디폴트로 활성화 합니다.(1~3)",MB_ICONMASK | MB_ABORTRETRYIGNORE|MB_DEFBUTTON3);

 

AfxMessageBox 자동으로 닫기

출처: http://k.daum.net/qna/view.html?category_id=QCA&qid=0CoCn&q=AfxMessageBox

 

저는 OnTimer를 이용해서 닫는 방법을 소개하지요.. 
Test란 이름으로 Project를 만들었을 경우 

void CTestDlg::OnTest() 

SetTimer(1, 500, NULL); 
AfxMessageBox("kdkdkd"); 


void CTestDlg::OnTimer(UINT nIDEvent) 

CString strCaption; // 윈도우 캡션 
CWnd* pWnd=AfxGetMainWnd()->GetWindow(GW_HWNDFIRST); 
while(pWnd) { 
if(pWnd->IsWindowVisible() && 
pWnd->GetWindowTextLength() && pWnd->GetOwner != NULL) { 
pWnd->GetWindowText(strCaption); 
if(strstr(strCaption,"TEST") != NULL) break; 

pWnd = pWnd->GetWindow(GW_HWNDNEXT); 


if(pWnd) 

pWnd->SendMessage(WM_CLOSE, 0, 0L); 
KillTimer(1); 

CDialog::OnTimer(nIDEvent); 
}

================================================

참고: http://msdn.microsoft.com/ko-kr/library/w0kywcw3.aspx

http://msdn.microsoft.com/ko-kr/library/as6se7cb.aspx

반응형
반응형

블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc..

by 송정헌




// 명령줄에 지정된 명령을 디스패치합니다.

// 응용 프로그램이 /RegServer, /Register, /Unregserver 또는 /Unregister로 시작된 경우 FALSE를 반환합니다.

if (!ProcessShellCommand(cmdInfo))

return FALSE;


ProcessShellCommand 가 호출되고 난 후 view 클래스의 OnInitialUpdate 함수가 호출됨을 알 수있다


이때 OnInitialUpdate 함수가 끝나면 다시 ProcessShellCommand 의 아래부터 실행된다

반응형
반응형

http://cafe.naver.com/cegui/139


http://cafe.naver.com/cegui/2 이글에서 혜윰님이 말씀하신 CEGUI::System::Destroy 라는 함수가 없더라구요...

그대신 CEGUI::System::GetInstance().detstroysingleton인가하는 메소드가 있긴한데

보호영역이라서 사용이않되고 영역을 변경해서 컴파일해봤지만 무수한 메모리릭은 그대로 나더라구요

그래서 cegui포럼을 검색해서 답을 찾았습니당...

 delete CEGUI::System::getSingletonPtr();

로  System의 싱글톤 클래스를 받아와서 해야되는거엿더구요 -ㅇ-;;;;킁

이걸해도 나는 메모리릭!!!!!!!!!!!!!!!!!!!!!!!!!!

누수추적해봣더니 Renderer에서 나오는 릭이엇습니다

고로  delete m_myRenderer; 를 해줬습니다     m_myRenderer는 CEGUI::DirectX9Renderer* 이고요 ㅎ

이랫더니 메모리 누수 빠이 빠이 ><

순서를 바꿔서 렌더러 부터 해제를 시켜봤더니 메모리 오류가 뜨더라구요.

System를 먼져 해제하면서 렌더러속에있는 텍스쳐를 먼져 삭제해주고 렌더링 객체를 삭제해야하는데

렌더링 객체부터 삭제하면 System이 렌더링객체속 텍스쳐를 삭제 못해줘서 뜨는듯 하더라구요

그러므로 System을 먼져 릴리즈후 렌더러를 릴리즈시켜주면 될꺼같네요

 

고로 정리하자면

 delete CEGUI::System::getSingletonPtr();      //CEGUI::System의 싱글톤 포인터를 받아와서 해제시킨다
 delete m_myRenderer;                                //CEGUI::DirectX9Renderer를 해제시킨다.

                                                               // delete는 System-> Renderer순으로

 

ps. 카테고리 선택하는데 cegui분석에 올릴려햇는데 않올려지네요 -ㅇ-;; 응용이라 할정도는 아니라서요;;

운영진님이 혹시 보신다면 글이동좀 부탁드릴꼐요 ㅠㅠ

반응형
반응형

http://blog.naver.com/wonjinho81/90121971442


xerces C++ 오픈 XML 라이브러리 컴파일 

2011/08/30 18:12

복사http://blog.naver.com/wonjinho81/90121971442


libxml2와 xerces를 놓고 개 갈등 하다가 xerces로 결정했다

아래 링크로 가서 이미 컴파일된 바이너리를 받아서 써도되고 소스를 받아서 컴파일해서 써도된다

난 VisualStudio2005로 컴파일 해본다

 

c++용 xerces 3.1.1 버전 소스 다운로드

http://xerces.apache.org/xerces-c/download.cgi

 

 

다운로드 하고 압축을 풀면

xerces-c-3.1.1/projects/Win32/VC8/xerces-all 경로에

xerces-all.sln  솔루션 파일이 있다 컴파일러 종류와 버전별로 솔루션 파일이 다 있어서 편리하다

 

VisualStudio2005로 열어서 솔루션 탐색기를 보면 xerces-all에 포함된 31개 프로젝트가 나타난다

 

프로젝트가 굉장히 많은데 이중에 밑에서 다섯번째 "XercesLib" 프로젝트가 xml 라이브러리이고

나머지 프로젝트는 exe를 생성하는 샘플 소스 프로젝트이다

따라서 "XercesLib" 프로젝트만 빌드하면된다

 

프로젝트 속성 - 구성관리자 - 활성 솔루션 구성.

 

ICU(international components for unicode)는 유니코드와 관련된 것같은데 ICU와 관련된

라이브러리 같은것들을 추가적으로 받아서 설정 해줘야하나보다

골치아프게 생겼으므로 ICU debug/ICU release는 그냥 넘어가고 나중에 유니코드 관련문제가 발생하면 그때 가서보자

(http://site.icu-project.org/ 참조)

 

dll로 만들어 쓰려면 debug/release 를 사용하면 되고

정적 라이브러리로 만들어 쓰려면 Static debug/Static release 를 사용하면 된다

 

 

소스가 있으므로 당연한 얘기겠지만 32비트 64비트 모두 빌드 가능하다

 

 

 

빌드 완료후 xerces-c-3.1.1/Build/Win32/VC8/Debug 에 dll과 임포트 라이브러리가 생성된다.

반응형
반응형


[CEGUI] CEImagesetEditor 실행시 CEGUISILLYImageCodec_d 혹은 CEGUISILLYImageCodec 을 찾을 수 없다는 에러  기타 / 프로그래밍관련 

2010/11/10 10:52

복사http://blog.naver.com/saram95/90099853121


[CEGUI] CEImagesetEditor 실행시 CEGUISILLYImageCodec_d 혹은 CEGUISILLYImageCodec 을 찾을 수 없다는 에러
* 아래 기준이 되는 버젼
CEGUI-SDK-0.6.1
CEImagesetEditor-0.6.1

CEImagesetEditor 를 실행할 경우

Debug 모드일 경우
CEImagesetEditor:OnInit - Error: DynamicModule::DynamicModule - Failed to load module 'CEGUISILLYImageCodec_d': The specified module could not be found.

Release 모드일 경우
CEImagesetEditor:OnInit - Error: DynamicModule::DynamicModule - Failed to load module 'CEGUISILLYImageCodec': The specified module could not be found.

메세지가 뜬다.

이 경우 DLL 파일들을 찾지 못하는 경우이다.
$(CEGUI)\bin 폴더에있는 아래 DLL 파일들을 해당 폴더에 넣어주면 된다. 
Debug 모드 경우
$(CE_IMAGESET_EDITOR)\bin 의 Debug 설정 폴더 에 아래 파일들을 넣어준다.
- CEGUIBase_d.dll 
- CEGUIExpatParser_d.dll 
- CEGUIFalagardWRBase_d.dll 
- CEGUISILLYImageCodec_d.dll 
- CEGUITGAImageCodec_d.dll (technically not needed, but always a good idea) 
- OpenGLGUIRenderer_d.dll 
- SILLY_d.dll


Release 모드 경우
$(CE_IMAGESET_EDITOR)\bin 의 Release 설정 폴더 에 아래 파일들을 넣어준다.
- CEGUIBase.dll 
- CEGUIExpatParser.dll 
- CEGUIFalagardWRBase.dll 
- CEGUISILLYImageCodec.dll 
- CEGUITGAImageCodec.dll (technically not needed, but always a good idea) 
- OpenGLGUIRenderer.dll 
- SILLY.dll

* SILLY_d.dll 또는 SILLY.dll 이 CEGUI에 없을 경우
SILLY-0.1.0 와 같은 SDK 나 LIB 들을 다운 받아 넣어준다.
후에 사용될경우를 생각하여 $(CEGUI)\bin 에 같이 넣어주자

반응형

'프로그래밍(Programming) > GUI' 카테고리의 다른 글

CEGUI 한글설정  (0) 2012.12.02
CEGUI 메모리 해제(릴리즈)  (0) 2012.11.27
[CEGUI] DirectX9/Direct3D 에서 사용하기  (0) 2012.11.19
CEGUI 설치 및 CEGUI VC++ 설정  (0) 2012.11.19
Native WPF 4 PropertyGrid  (1) 2012.11.19
반응형




#ifdef _DEBUG
#pragma comment( lib, "CEGUIBase_d.lib" )
#pragma comment( lib, "CEGUIDirect3D9Renderer_d.lib" )
#else
#pragma comment( lib, "CEGUIBase.lib" )
#pragma comment( lib, "CEGUIDirect3D9Renderer.lib" )
#endif

이부분을제거하고  각각 Debug, Release 모드에 해당 lib 를 속성-링크-입력에서 넣어도 됨




[CEGUI] DirectX9/Direct3D 에서 사용하기  CEGUI / 게임개발 

2012/02/02 17:34

복사http://hsengine.co.kr/20149812028


 [CEGUI] DirectX/Direct3D 에서 사용하기

CEGUI를 DirectX/Direct3D/다이렉트/다이렉트X 에 이용해서 간단히 윈도우를 띄어보겠다. 

HSEngine을 이용하지만 DirectX와 사용하는게 같으니 수정해서 사용해야 한다. 

 

 

선언:

#include <CEGUI.h>
#include <RendererModules\Direct3D9\CEGUIDirect3D9Renderer.h>
#ifdef _DEBUG
#pragma comment( lib, "CEGUIBase_d.lib" )
#pragma comment( lib, "CEGUIDirect3D9Renderer_d.lib" )
#else
#pragma comment( lib, "CEGUIBase.lib" )
#pragma comment( lib, "CEGUIDirect3D9Renderer.lib" )
#endif
CEGUI::Direct3D9Renderer* myRenderer;
 
초기화:
    CEGUI::Direct3D9Renderer& myRenderer = CEGUI::Direct3D9Renderer::bootstrapSystem( HSE.m_pd3dDevice );
    CEGUI::Renderer *pRenderer = CEGUI::System::getSingleton().getRenderer();
    CEGUI::Direct3D9Renderer* Renderer = static_cast<CEGUI::Direct3D9Renderer*>(pRenderer);
    Renderer->postD3DReset();

    CEGUI::DefaultResourceProvider* rp = 
               static_cast<CEGUI::DefaultResourceProvider*>(CEGUI::System::getSingleton().getResourceProvider());

    rp->setResourceGroupDirectory("schemes", "datafiles/schemes/");
    rp->setResourceGroupDirectory("imagesets", "datafiles/imagesets/");
    rp->setResourceGroupDirectory("fonts", "datafiles/fonts/");
    rp->setResourceGroupDirectory("layouts", "datafiles/layouts/");
    rp->setResourceGroupDirectory("looknfeels", "datafiles/looknfeel/");
    rp->setResourceGroupDirectory("lua_scripts", "datafiles/lua_scripts/");


    CEGUI::Imageset::setDefaultResourceGroup("imagesets");
    CEGUI::Font::setDefaultResourceGroup("fonts");
    CEGUI::Scheme::setDefaultResourceGroup("schemes");
    CEGUI::WidgetLookManager::setDefaultResourceGroup("looknfeels");
    CEGUI::WindowManager::setDefaultResourceGroup("layouts");
    CEGUI::ScriptModule::setDefaultResourceGroup("lua_scripts");

    SchemeManager::getSingleton().create("TaharezLook.scheme");

    System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow");

    WindowManager& winMgr = WindowManager::getSingleton();
    DefaultWindow* root = (DefaultWindow*)winMgr.createWindow("DefaultWindow", "Root");
    System::getSingleton().setGUISheet(root);

    FrameWindow* wnd = (FrameWindow*)winMgr.createWindow("TaharezLook/FrameWindow", "Demo Window");
    root->addChildWindow(wnd);
    wnd->setPosition(UVector2(cegui_reldim(0.25f), cegui_reldim( 0.25f)));
    wnd->setSize(UVector2(cegui_reldim(0.5f), cegui_reldim( 0.5f)));
    wnd->setMaxSize(UVector2(cegui_reldim(1.0f), cegui_reldim( 1.0f)));
    wnd->setMinSize(UVector2(cegui_reldim(0.1f), cegui_reldim( 0.1f)));
    wnd->setText("Hello World!");


    FrameWindow* wnd2 = (FrameWindow*)winMgr.createWindow("TaharezLook/FrameWindow", "Demo Window2");
    root->addChildWindow(wnd2);
    wnd2->setPosition(UVector2(cegui_reldim(0.0f), cegui_reldim( 0.0f)));
    wnd2->setSize(UVector2(cegui_reldim(0.5f), cegui_reldim( 0.5f)));
    wnd2->setMaxSize(UVector2(cegui_reldim(1.0f), cegui_reldim( 1.0f)));
    wnd2->setMinSize(UVector2(cegui_reldim(0.1f), cegui_reldim( 0.1f)));
    wnd2->setText("HSEngine");
 
키보드와 마우스관련 CEGUI로 넘겨주기:(직접짠 클래스에 맞게 되어있으므로 수정해야된다.)

float dt=HSE.dt; CEGUI::System * ceguiPtr = CEGUI::System::getSingletonPtr(); ceguiPtr->injectTimePulse( dt ); ceguiPtr->injectMousePosition(HSObject::m_HSInput.x, HSObject::m_HSInput.y); if(HSObject::m_HSInput.BtnDown(0)) CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::LeftButton); if(HSObject::m_HSInput.BtnDown(1)) CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::RightButton); if(HSObject::m_HSInput.BtnDown(2)) CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::MiddleButton); if(HSObject::m_HSInput.BtnUp(0)) CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::LeftButton); if(HSObject::m_HSInput.BtnUp(1)) CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::RightButton); if(HSObject::m_HSInput.BtnUp(2)) CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::MiddleButton);

반응형
반응형

블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc..

by 송정헌




CEGUI.sin 와 CEGUISamples.sin 의 각 프로젝트 전체에 아래와 같이 파일을 포함한다 




[include]

C:\CEGUI\include;C:\CEGUI\cegui\include;C:\CEGUI\cegui\include\elements;

C:\CEGUI\cegui\include\falagard;C:\CEGUI\cegui\include\RendererModules\Direct3D9



[lib]

C:\CEGUI\lib;C:\CEGUI\lib\dynamic;C:\CEGUI\lib\ReleaseWithSymbols;C:\CEGUI\lib\static



위의 것을 복사해 붙여넣고 다이렉트는 자신의 로컬경로에서 포함시키면 됨







[CEGUI] CEGUI 설치 및 CEGUI VC++ 설정  

2012/02/02 17:23

복사http://hsengine.co.kr/20149811131


 CEGUI 설치와 CEGUI VC++ 설정

 

cegui 설치방법과 cegui 설정하는 방법에 대해 설명하겠다.

CEGUI를 다운받기 위해 CEGUI 사이트에 접속한다.

 

http://www.cegui.org.uk/wiki/index.php/Downloads 

 

 

 

Crazy Eddie's GUI System - Downloads 에서 최신버전을 클릭한다.

 

Library Source Downloads에서 운영체제에 맞는 소스코드를 다운받는다.

 

그리고 Binary Dependency Downloads for MSVC++에서 VC++버전에 맞는것을 찾아 다운받는다.

 

 

Library Source Downloads에서 다운받는 압축파일을 풀고. (예: C:\CEGUI)

 

Binary Dependency Downloads for MSVC++에서 받은 압축파일을 열어 dependencies 폴더안에 있는 파일들을 아까 압축푼곳에 압축을 풀어 덮어쓴다. 

 

이제 C:\CEGUI\projects\premake 로 이동한다.

 

여기서 오우거엔진이나 일리히트엔진에 이용할꺼면 config.lua 파일을 수정해야된다.

 

config.lua파일에 찾아보면 아래와 같은 내용이 있다.

 

자신에 맞게 직접 수정해주면 된다. (Direct3D9을 이용할꺼면 따로 수정하지 않아도 된다.)

 

그리고 오우거나 일리히트엔진은 따로 경로 설정을 해야된다.

 

 

이제  build_vs2008.bat 파일와 build_samples_vs2008.bat을 실행한다. (버전에 맞는걸로 실행)

 

 

 

 

그러면 CEGUI.sln, CEGUISamples.sln 파일이 생성된다.

 

열어서 빌드만 해주면 된다.

 

C:\CEGUI\bin 폴더에서 Samples 들을 실행해볼 수 있다.

 

 

VC++ 설정

 

 

lib

C:\CEGUI\lib

C:\CEGUI\lib\dynamic

C:\CEGUI\lib\ReleaseWithSymbols

C:\CEGUI\lib\static

 

include

C:\CEGUI\include

C:\CEGUI\cegui\include

C:\CEGUI\cegui\include\elements

C:\CEGUI\cegui\include\falagard

C:\CEGUI\cegui\include\RendererModules\Direct3D9 (여기서 Direct3D9 대신 Irrlicht, Ogre, OpenGL, Direct3D10 등.. 추가할 수 있다. 자신이 사용할것에 따라 설정한다.)

 

반응형
반응형

 

다운주소 http://www.codeproject.com/Articles/87715/Native-WPF-4-PropertyGrid

 

 

 

 


출처 : http://gamedevforever.tistory.com/211

 

 

 

툴의 꽃 프러퍼티 그리드를 사용해보자 ( PropertyGrid for WPF )

 
 
 

게임을 제작하게 되면 게임에 등장하는 여러 오브젝트들을 만들게 됩니다. 그런데 이 오브젝트들은 많은 속성 값을 가지게 됩니다. 위치라든가, 크기, 속도, 텍스쳐는 어느 것을 쓰는지, 이 객체에 쓰일 이펙트는 어떤 것인지 같은 것 말입니다. 보통 이런 속성 값들은 툴을 이용해 제어하게 됩니다. 그런데, 이 속성 값들을 지정해주기 위해서는 입력 필드가 필요하겠지요?

 

윈폼이나 WPF에서는 체크박스, 텍스트박스 같은 기본 컨트롤등이 제공되고 있습니다. 이 컨트롤들을 이용해 위에서 말한 속성 값들을 정의 할 수 있습니다. 하지만 많은 수의 속성 값들을 제어 하기에는 역부족입니다. 각각의 오브젝트들이 같은 속성 값을 가지고 있는 것도 아니고, 오브젝트 종류에 따라 많게는 수십가지의 속성 값을 필요로 하는데 이 많은 속성 값들을 위한 입력 필드들을 재구성하고, 추가하는 것을 만들라 하면 누구라도 멘붕이 올 것입니다.

 

벌써 부터 하기 싫어진다...

 

수많은 속성 값들을 손쉽게 제어할수 있는 컨트롤이 있으면 어떨까요? 게다가 제작도 간편해야 합니다. 툴을 만들때 딱! 하니 뙇! 하고 나와주면 얼마나 좋겠습니까? 그런데 그게 실제로 존재합니다.

 


ㅋㅋㅋㅋ

 

그게 무엇인지 알아보기 전에 다른 이름 있는 게임 엔진 툴들은 이것을 어떻게 처리 하고 있는지 한번 살펴 보죠.

 

 

 

 

 

내노라 하는 게임 엔진들을 보면 항상 보이는 놈이있죠. 직접 툴을 만들어 보시면서 사용해보신 분들도 계실겁니다. 바로 프로퍼티 그리드 ( Property Grid )죠. 이 프로퍼티 그리드는 그 이름 답게 수많은 속성 값들을 제어할수 있게 도와주는 아주 유용한 컨트롤입니다. 특히 이 프로퍼티 그리드가 유용한 이유 중 하나가 바로 다양한 타입의 값들을 제어 할수 있다는 것입니다.


툴에서 사용되는 많은 속성 값들은 타입이 제각각 입니다. 단순 불린 ( Boolean ) 타입 부터 정수, 실수는 물론이고, Point, Vector3/4, 16진수 컬러값까지 다양한 값들이 존재합니다. 프로퍼티 그리드는 이런 다양한 타입들을 한 곳에서 제어할수 있는 수단을 제공해주죠. 불린은 체크박스 형태로, 스핀 컨트롤로 정교한 실수값 설정, 브러시 컨트롤을 이용한 색 추출, 그리고 포인트나 벡터 같이 동시에 다수의 값들이 필요한 타입까지도 말이지요.

 

좋습니다. 그렇다면 어떻게 해야 이 프로퍼티 그리드라는 놈을 내가 만드는 툴에 뙇~ 하고 넣을 수 있을까요? 안타깝게도 이 프로퍼티 그리드라는 놈은 WPF에서 기본으로 제공해주는 컨트롤이 아닙니다.


이런 고자 같은 WPF 같으니...

 

그렇다면 어떻게 WPF에서 프로퍼티 그리드를 사용해야 하는가? 고맙게도 이미 많은 능력자 분들께서 WPF에서 프로퍼티 그리드를 사용할수 있게 만들어 공개해두셨습니다. MS도 참 웃긴게 비쥬얼 스튜디오 Visual Studio 에서도 사용 되는 컨트롤을 왜 기본으로 제공 안해주는지 모르겠습니다(블렌드 Blend 같은 툴 팔아먹으려고 그러는 것 같아요).

 

일단 제가 찾아서 사용해본 몇몇 프로퍼티 그리드등이 있는데, 각각 구현 방식도 다르고, 비쥬얼도 다르지만 가장 제대로 작동하고, 사용하기 쉬웠던 것은 Jaime Olivares 라는 분이 만드신 Native WPF 4 PropertyGrid 였습니다.

 

 

프로퍼티 그리드를 사용하기 위해서는 먼저 C#의 프로퍼티에 대해 알아야합니다. 이 프로퍼티 기능은 C++ 식으로 말하면 일종의 Getter/Setter 인터페이스라고 할수 있습니다. 소스를 보시면 쉽게 이해 되실 겁니다.

  1. public class Person  
  2. {  
  3.     public enum Gender { Male, Female }  
  4.   
  5.     private string m_strName;  
  6.     private int m_iAge;  
  7.     private Gender m_eGender;  
  8.   
  9.     public Person()  
  10.     {  
  11.         m_strName = "친절한티스";  
  12.         m_iAge = 21;  
  13.         m_eGender = Gender.Male;  
  14.     }  
  15.   
  16.     public string nameProp  
  17.     {  
  18.         set { m_strName = value; }  
  19.         get { return m_strName; }  
  20.     }  
  21.   
  22.     public int ageProp  
  23.     {  
  24.         set { m_iAge = value; }  
  25.         get { return m_iAge; }  
  26.     }  
  27.   
  28.     public Gender genderProp  
  29.     {  
  30.         set { m_eGender = value; }  
  31.         get { return m_eGender; }  
  32.     }  
  33. }  

멤버 변수는 private 으로 설정 되어있고, 그 멤버 변수에 대한 nameProp, ageProp, genderProp 프로퍼티들이 선언 되어있습니다. 외부에서 멤버 변수의 값을 쓰거나 읽을때 이 프로퍼티들을 이용하게 되죠.

  1. Person prop = new Person();  
  2. prop.nameProp = "김포프";  
  3. prop.ageProp = 22;  
  4. prop.genderProp = Person.Gender.Female;  

...이렇게 말이죠.

 

갑자기 C#의 프로퍼티 기능에 대해서는 왜 말하는 거지? 하고 의아해 하실 수 있는데, 프로퍼티 그리드가 바로 이 프로퍼티 기능을 이용하기 때문입니다. 게다가 무려 프로퍼티를 선언해 두면 프로퍼티 그리드에서 알아서 컨트롤에 생성을 해줍니다!!!!!!!

 

그렇다면 정말로 프로퍼티 그리드에 위의 속성값들이 나오는지 만들어보겠습니다. 두큰두큰~ 위에서 받은 WpfPropertyGrid.cs 파일을 프로젝트에 추가 해주고 아래 그림과 같이 프로젝트에 참조를 추가 해줍니다.

 

 

그리고 프로퍼티 그리드를 추가할 윈도우 xaml 파일을 열어 아래와 같이 추가해줍니다.

 

 

이제 프로퍼티 그리드에 표시해줄 속성 값을 가지고 있는 오브젝트를 생성해서 적용해주면 됩니다.
  1. public MainWindow()  
  2. {  
  3.     InitializeComponent();  
  4.   
  5.     Person prop = new Person();  
  6.     prop.nameProp = "김포프";  
  7.     prop.ageProp = 22;  
  8.     prop.genderProp = Person.Gender.Female;  
  9.   
  10.     // 프로퍼티 그리드에 적용  
  11.     propertyGrid1.SelectedObject = prop;  
  12. }  

끝입니다. 참쉽죠? 정말 제대로 나올까요? 한번 실행해보겠습니다.

 

 

22살의 아리따리운 미소녀 김포프 프로퍼티 그리드가 나타났습니다. 우왕~ 그런데 좀 이상하군요. 카테고리 분류도 없고, 속성값 이름도 프로퍼티 이름이 그대로 나옵니다. 다른 엔진 툴에서 사용되는 프로퍼티 그리드를 보면 카테고리도 잘 분류되어있고, 속성값 이름들도 그럴싸하게 명명되어 있는데 말이죠. 이를 바꿔주기 위해서는 C#의 Attributes를 이용해주어야 합니다.

  1. public class Person  
  2. {  
  3.     public enum Gender { Male, Female }  
  4.   
  5.     private string m_strName;  
  6.     private int m_iAge;  
  7.     private Gender m_eGender;  
  8.   
  9.     public Person()  
  10.     {  
  11.         m_strName = "박기헌";  
  12.         m_iAge = 31;  
  13.         m_eGender = Gender.Male;  
  14.     }  
  15.   
  16.     [Category("인적사항")]  
  17.     [DisplayName("이름")]  
  18.     public string nameProp  
  19.     {  
  20.         set { m_strName = value; }  
  21.         get { return m_strName; }  
  22.     }  
  23.   
  24.     [Category("인적사항")]  
  25.     [DisplayName("나이")]  
  26.     public int ageProp  
  27.     {  
  28.         set { m_iAge = value; }  
  29.         get { return m_iAge; }  
  30.     }  
  31.   
  32.     [Category("기타등등")]  
  33.     [DisplayName("성별")]  
  34.     public Gender genderProp  
  35.     {  
  36.         set { m_eGender = value; }  
  37.         get { return m_eGender; }  
  38.     }  
  39. }  

Category와 DisplayName Attributes를 추가 하였습니다. 어떻게 바뀌었을까요?



카테고리가 생겼고, 속성 값명도 지정해준대로 잘 나옵니다. 짝짝짝~~...계속
( 예상보다 내용이 너무 길어져서... 상하로 나눠서 써야 할것 같군요. 진짜 연재가 되어버렸네... )







 

 

지난 글에서 WPF에 프로퍼티 그리드를 적용하는 방법을 살펴 보았습니다. 이 것으로 다양한 속성 값들을 툴에서 컨트롤 할수 있게 되었죠. 그런데 앞서 언급했던 것처럼 여러 속성 값들의 타입이 각자 제각각입니다. 그 중 많이 쓰이는 타입 중 하나가 벡터3 ( Vector3 )이 있습니다. 위치를 나타낼때 많이 쓰이는 이 타입의 값을 프로퍼티 그리드에서 어떻게 표시해야 될까요? 아마 밑의 그림과 같이 표시할 수도 있을 겁니다.

 

 

벡터3의 x, y, z 성분들을 각각 하나의 값으로 보고 값을 입력 받을수 있도록 하는 것이죠. 하지만 벡터3의 타입이 많이 쓰이게 된다면 관리 해야될 속성값이 기하급수적으로 늘어나게 될 것입니다. 다른 방법은 없을까요?

 

보통 엔진단에서 보면 벡터를 하나의 타입으로 간주하고 사용을 합니다. 툴에서도 같은 식으로 써야 논리적으로 맞을것 같습니다. 벡터 클래스를 하나 만들기로 하죠.

  1. // 간단한 벡터3 타입 클래스  
  2. public class Vector3  
  3. {  
  4.     public float m_fX;  
  5.     public float m_fY;  
  6.     public float m_fZ;  
  7.   
  8.     public Vector3()  
  9.     {  
  10.         m_fX = 0;  
  11.         m_fY = 0;  
  12.         m_fZ = 0;  
  13.     }  
  14. }  

그리고 이 클래스를 프로퍼티 그리드에 등록하겠습니다.

  1. // 중복 코드는 생략  
  2. public class Person  
  3. {  
  4.     private Vector3 m_vLocate;  
  5.   
  6.     [Category("기타등등")]  
  7.     [DisplayName("위치")]  
  8.     public Vector3 locProp  
  9.     {  
  10.         set { m_vLocate = value; }  
  11.         get { return m_vLocate; }  
  12.     }  
  13. }  

한번 실행해 보죠.

 

 

프로퍼티 그리드에 등록은 되는 것 같습니다. 하지만 값을 입력할라 치면, 아래와 같은 오류 메시지가 뜹니다.

 

 

이유는 입력한 값을 Vector3 타입으로 변환 할수 없기 때문입니다. 즉, 입력한 값 ( 보통 문자열 )에서 Vector3 타입으로 변환해 줄수 있는 변환기가 필요하다는 것 입니다. 그렇다면 변환기를 만들어주도록 하죠.

  1. // Vector3 변환기  
  2. public class Vector3Convter : TypeConverter  
  3. {  
  4.     // string 으로 부터 변환이 가능한가?  
  5.     public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)  
  6.     {  
  7.         if (sourceType == typeof(string))  
  8.         {  
  9.             return true;  
  10.         }  
  11.         return base.CanConvertFrom(context, sourceType);  
  12.     }  
  13.   
  14.     // string 으로 부터 vector3로 변환  
  15.     public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)  
  16.     {  
  17.         if (value is string)  
  18.         {  
  19.             string[] v = ((string)value).Split(new char[] { ',' });  
  20.             return new Vector3(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]));  
  21.         }  
  22.         return base.ConvertFrom(context, culture, value);  
  23.     }  
  24.   
  25.     // vector3 에서 string으로 변환  
  26.     public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)  
  27.     {  
  28.         if (destinationType == typeof(string))  
  29.         {  
  30.             return ((Vector3)value).m_fX + "," + ((Vector3)value).m_fY + "," + ((Vector3)value).m_fZ;  
  31.         }  
  32.         return base.ConvertTo(context, culture, value, destinationType);  
  33.     }  
  34. }  

변환기를 만들어 주기 위해서는 TypeConver 클래스를 상속 받아 CanConvertFrom, CanvertFrom, CanConvertTo, ConvertTo 4가지 함수를 재정의 해주어야 합니다. 여기서는 CanConvertTo가 그닥 필요치 않아 생략 되었습니다( 자세한 내용은 MSDN 참조 ). 변환기 클래스를 만들었으면 이제 벡터3 프로퍼티에 변환기를 등록해줍니다.

  1. // 중복 코드는 생략  
  2. public class Person  
  3. {  
  4.     private Vector3 m_vLocate;  
  5.   
  6.     [Category("기타등등")]  
  7.     [DisplayName("위치")]  
  8.     [TypeConverter(typeof(Vector3Convter))] // 변환기 등록  
  9.     public Vector3 locProp  
  10.     {  
  11.         set { m_vLocate = value; }  
  12.         get { return m_vLocate; }  
  13.     }  
  14. }  

이제 프로퍼티 그리드에서 벡터3 타입이 제대로 입출력 되는지 확인해보도록 하죠.


 

 

 

실행을 해보니 벡터3의 기본값인 0, 0, 0이 출력됩니다. 그리고 10, 55, 38을 입력하면, 아까와 같은 오류 없이 제대로 입력이 됩니다. ( 그외 맞지 않는 문자열등이 입력될 때를 대비해 변환기에서 예외처리를 해주면 좋습니다 )

 

이처럼 변환기를 통해 기본 타입 이외의 타입들을 관리 할수 있는 방법을 알아봤습니다. 하지만 여기서 좀더 유저 편의성을 높일수 있는 방법이 있습니다. 예로 특정 정수값이 있는데, 이 값은 0 ~ 100까지 값을 가집니다. 그런데 이 값을 직접 입력받는 것이 아니라 슬라이더 컨트롤러(Slider)를 이용해 값을 정할수 있다면 어떨까요? 사용자 입장에서도 꽤나 편리 할것 같습니다.
프로퍼티 그리드에 기본적으로 제공되는 기본 컨틀롤러 이외의 커스텀 컨트롤러를 추가하는 방법을 알아보겠습니다. 위에 이야기한 슬라이더 컨트롤러를 추가해보도록 하죠.
  1. public class CustomSlider : ExtendedPropertyValueEditor  
  2. {  
  3.     public CustomSlider()  
  4.     {  
  5.         // Template for normal view  
  6.         string template1 = @"  
  7.             <DataTemplate  
  8.                 xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'  
  9.                 xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'  
  10.                 xmlns:pe='clr-namespace:System.Activities.Presentation.PropertyEditing;assembly=System.Activities.Presentation'   
  11.                 xmlns:wpg='clr-namespace:PropertyGrid;assembly=PropertyGrid' >   
  12.                 <DockPanel LastChildFill='True'>  
  13.                         <TextBox Text='' Width='40' TextAlignment='Center' />  
  14.                         <Slider x:Name='slider1' Value='' Margin='2,0,0,0' Minimum='' Maximum='' />  
  15.                 </DockPanel>  
  16.             </DataTemplate>";  
  17.   
  18.         // Load templates  
  19.         using( var sr = new MemoryStream( Encoding.UTF8.GetBytes( template1 ) ) )  
  20.         {  
  21.             this.InlineEditorTemplate = XamlReader.Load( sr ) as DataTemplate;  
  22.         }  
  23.     }  
  24. }  
먼저 ExtendedPropertyValueEditor 클래스를 상속 받아 CustomSlider 클래스를 만듭니다. 그 다음 XAML을 통해 슬라이더 컨트롤러 DataTemplate을 구성합니다. 여기서 끝이 아닙니다. 이 컨트롤러와 바인딩할 객체가 있어야합니다. 즉, 슬라이드를 움직이면 그 슬라이더 값이 저장될 곳이 있어야 합니다. 위 코드를 보면 미리 Binding Value.xxx 형태로 바인딩이 적용되어있습니다. 
슬라이더 컨트롤러의 경우 현재값, 최소값, 최대값, 단계값 총 4개의 값이 필요합니다. 이를 위해 따로 슬라이더 컨트롤러를 위한 클래스를 하나 정의해주도록 하겠습니다.
  1. public class SliderValue<T>  
  2. {  
  3.     public SliderValue(T value, T min, T max, T step)  
  4.     {  
  5.         Value = value;  
  6.         Min = min;  
  7.         Max = max;  
  8.         Step = step;  
  9.     }  
  10.   
  11.     public T Value { getset; }  
  12.     public T Max { getset; }  
  13.     public T Min { getset; }  
  14.     public T Step { getset; }  
  15. }  
이제 실제로 슬라이더 컨트롤러를 프로퍼티 그리드에 사용해보도록 하겠습니다.
  1. // 중복 코드 생략  
  2. public class Person  
  3. {  
  4.     private SliderValue<int> m_iAge;  
  5.   
  6.     public Person()  
  7.     {  
  8.         m_iAge = new SliderValue<int>(22, 0, 100, 1);  
  9.     }  
  10.   
  11.     [Category("인적사항")]  
  12.     [DisplayName("나이")]  
  13.     [Editor(typeof(CustomSlider), typeof(PropertyValueEditor))]  
  14.     public SliderValue<int> ageProp  
  15.     {  
  16.         set { m_iAge = value; }  
  17.         get { return m_iAge; }  
  18.     }  
  19. }  


실제 슬라이더 컨트롤러가 적용된 스샷입니다. 슬라이더를 움직이면 0 부터 100까지 값을 조절할수 있고, 직접 값을 입력하면 슬라이더 컨트롤러도 같이 움직이는 것을 확인할 수 있습니다. 단, 직접 입력시에는 0~100까지 제한이라는 예외처리가 안되어있기 때문에 이를 위해서는 추가 작업을 해주어야 합니다.
위의 슬라이더 컨트롤러 XAML을 살펴보면 UpdateSourceTrigger=PropertyChanged 라는 구문이 있습니다. 이는 값이 변경 되었을때 PropertyChanged 이벤트를 날려주기 위함이지요. 이 이벤트를 받는 방법을 구현해보도록 하겠습니다. 

PropertyChanged 이벤트를 받기 위해서는 INotifyPropertyChanged 클래스를 상속 받아야 합니다. 앞서 구현한 SliderValue 클래스를 조금 수정하도록 하겠습니다.

  1. // 중복 코드 생략  
  2. public class SliderValue<T> : INotifyPropertyChanged  
  3. {  
  4.     private T mValue;  
  5.     public T Value  
  6.     {  
  7.         get  
  8.         {   
  9.             return mValue;  
  10.         }  
  11.         set  
  12.         {  
  13.             mValue = value;  
  14.             OnPropertyChanged("Value");  
  15.         }  
  16.     }  
  17.  
  18.     #region INotifyPropertyChanged Members  
  19.     public event PropertyChangedEventHandler PropertyChanged;  
  20.     private void OnPropertyChanged(String info)  
  21.     {  
  22.         if (PropertyChanged != null)  
  23.         {  
  24.             PropertyChanged(thisnew PropertyChangedEventArgs(info));  
  25.         }  
  26.     }  
  27.     #endregion  
  28. }  

이제 슬라이더 컨트롤러를 통해 값이 변경 되면 PropertyChanged 이벤트를 받을수 있게 되었습니다. 슬라이더 컨트롤러를 사용하는 Person 클래스에 슬라이더 컨트롤러의 PropertyChanged 이벤트를 받을수 있는 콜백 함수를 등록 하면 슬라이더 컨트롤러의 값이 변경 되었을 때의 작업을 수행할 수 있습니다.

  1. public class Person  
  2. {  
  3.     public Person()  
  4.     {  
  5.         m_iAge = new SliderValue<int>(22, 0, 100, 1);  
  6.         m_iAge.PropertyChanged += new PropertyChangedEventHandler(SliderPropChanged);  
  7.     }  
  8.   
  9.     // CustomSlider에서 값이 변경 되었다~  
  10.     private void SliderPropChanged(object sender, PropertyChangedEventArgs e)  
  11.     {  
  12.         if (e != null)  
  13.         {  
  14.         }  
  15.     }  
  16. }  
  17.  

 

 

반응형
반응형

http://www.soenlab.com/




반응형
반응형


http://cafe.naver.com/sunschool/69




표준 입출력 처리


 

iostream 클래스는 전역적으로 생성되어 사용할 수 있는 4개의 입출력을 처리하는 전역 오브젝트를 제공한다.

 

cin 오브젝트

cin오브젝트는 키보드로 부터 문자를 읽어들인다. 추출연산자 ">>"을 사용한다.

cin >> name >> address;

 

istream_withassaign클래스의 미리 정의된 오브젝트이다. cin전역 오브젝트는 다음과 같이 선언되어 있다.

extern _CRTIMP istream_withassign cin;

 

16진수나 8진수 값을 입력받기위해 조작자(manipulator)을 사용한다.

hex : 16진수로 입력

oct  : 8진수로 입력

dec : 10진수로 입력

ex) cin >> hex >> a >> oct >> b;

cout 오브젝트

화면에 문자를 출력한다. 삽입연산자 "<<"을 사용한다.

cout << "안녕하세요!!!!";

조작자(manipulator)

             endl  : 개행문자를 삽입한후 버퍼를 플러쉬한다.

             ends : 널문자를 삽입한다.

             flush : 출력버퍼를 플러쉬한다.

폭지정

             width() 멤버함수를 호출한다.

             ex)

cout << “%%%%”;

             cout.width(20);

         cout << “100” << endl;

             setw 조작자를 사용한다.

              cout << setw(10) << “This” << setw(10) << “is” << setw(20) << “Test” << endl;

소수점 처리

             부동소수점에 대해서는 기본적으로 6자리까지 표현된다.  소수점 표현방법을 변경하기 위해서는 setprecision 조작자를 사용한다.

cout << setprecision(1) << 100.1234;  // 소수점 이하 한자리만 표시한다.

기본적인 표시법은 과학기술계산용(ios::scientific)표기법을 사용한다. 이러한 표기법을 사용하지 않으려면 “ios::fixed”를 매개변수로 setioflags 조작자를 사용한다.

cout << setiosflags(ios::fixed) << 1000000000 << endl;

 

cerr 오브젝트

표준에러장치(화면)에 에러를 출력한다.(단위버퍼링-한행이 채워질때 이들 정보를 화면에 출력-을 사용한다)

 

clog 오브젝트

표준에러장치(화면)에 에러를 출력한다.(완전한 버퍼링-명확히 플러시될때까지 여러해에 걸쳐 정보를 저장-을 사용한다)

 

 

파일 입출력 처리

파일 입출력을 위해서는 다음과 같은 세가지 종류의 클래스를 사용한다.

ifstream : 입력 파일 스트림 클래스

ofstream : 출력 파일 스트림 클래스

fstream : 입출력 파일 스트림 클래스

 

파일 열기와 닫기

출력파일 열기

ofstram outfile(“test.dat”); 

if(!outfile)                         // if(!outfile.is_open()) 로 점검하여도 된다.

cout << “파일 오픈 에러”;

else

    cout << “파일 정상적으로 오픈 되었습니다”

outfile.close()   // 파일을 닫는다.

 

입력파일열기

Ifstream infile(“read.dat”);  // 이경우 파일이 존재하지 않으면 생성한다. 파일존재하지 않는경우 생성하지 않으려면

If(!infile)                           // ifstream infile(“read.dat”,ios::nocreate) 형식으로 오픈하여야 한다.

cout << “file open error”;

else

cout << “file open successed”;

 

open 멤버함수에 사용되는 열거형 매개변수

ios::binary

이진모드로 파일 열기(기본은 텍스트 모드이다)

ios::app

파일의 끝에 추가한다

ios::ate

처음에는 파일끝에 추가되지만 그 다음부터는 현재 위치에 추가된다.

ios::in

읽기모드로 파일을 연다

ios::out

쓰기모드로 파일을 연다

ios::trunc

이미 파일이 있는경우 내용을 삭제한다

ios::nocreate

파일이 없으면 에러가 발생된다

ios::noreplace

이미 파일이 있으면 에러가 발생된다.

 

파일에 읽고 쓰기

char ch;

char buffer[81];

ifstream inputfile(“read.dat”);

 

inputfile >> ch;   // 파일로부터 한문자 읽어들인다.

inputfile >> buffer  // 공백문자로 구별되는 한단어를 읽어들인다.

ch=inputfile.get();

inputfile.get(ch);

 

inputfile.get(buffer,80);  // 하나의 레코드가 80바이트 이하이면 ‘\n’ 이 나타날 때 까지 데이터를 읽어 buffer에 저장하고 80바이트 이상이면 80바이트까지 읽어서 buffer에 저장한다.

inputfile.getline(buffer,80) // get과 같지만 ‘\n’문자를 읽어는 들이지만 저장하지는 않는다.

 

ofstream outfile(“test.data”);

outfile << buffer << endl;

 

이진 파일에 읽고 쓰기

char buffer[80];

int nCount=80;

ifstream infile(“test.dat”,ios::in|ios::binary);

ofstream outfile(“write.dat”,ios::out|ios::binary);

while(nCount==80)

{

           infile.read(buffer,80);

nCount=infile.gcount();

outfile.write(buffer,80);

if(outfile.rdstat() != ios::goodbit)

             cerr<< “write error!!”;

}

infile.close();

outfile.close();

반응형
반응형

블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc..





#include <string>


namespace st=std;

st::string str;



처럼 사용할 수 있다 이렇게 쓰면 별 쓸모없어보이지만 아래처럼 네임스페이스가 여러개 포함될때 유용하게 쓰일 수 있다



namespace fs = boost::filesystem;




반응형
반응형


http://saelly.tistory.com/128



new 연산자 오버로딩


new, delete 연산자의 오버로딩은 다른 연산자 오버로딩과 많이 다르다!!

이 둘은 분명 연산자이다. 따라서 연산자 오버로딩이 가능하며, 이 둘을 이용해서 클래스 별로 독특한 객체의 생성과정을 정의할 수도 있다. 그런데 이 둘에 대한 연산자 오버로딩은 이전에 보았던 연산자 오버로딩과는 다소 차이가 있다.


기본적으로 제공되는 new 연산자가 하는 일


1. 메모리 공간의 할당

2. 생성자의 호출

3. 할당하고자 하는 자료형에 맞게 반환된 주소 값의 형 변환


new 연산자가 진행하는 세 가지 작업 중에서 1번에 해당하는 메모리 공간의 할당만 오버로딩 할 수 있다,


다음과 같이 오버로딩 하도록 이미 약속이 되어있다

void* operator new(size_t size) {    }

반환형은 반드시 void 포인터 형이어야 하고, 매개변수는형은 size_t이어야 한다.


※ 일반적으로 size_t 는 다음과 같이 정의되어 있다.

typedef unsigned int size_t;

그래서 0 이상의 값을 표현할 목적으로 정의된 자료형이다.


※ 크기정보는 바이트 단위로 계산되어 전달된다.




delete 연산자 오버로


delete ptr; 이것의 문장으로 객체의 소멸을 명령하면,

컴파일러는 먼저 ptr이 가리키는 객체의 소멸자를 호출한다. 그리고는 다음의 형태로 정의된 함수에 ptr에 저장된 주소 값을 전달한다.

void operator delete(void* adr){    }


따라서 delete 함수는 다음의 형태로 정의해야 한다. 즉, 소멸자는 오버로딩 된 함수가 호출되기 전에 호출이 되니 오버로딩 된 함수에서는 메모리 공간의 소멸을 책임져야 한다. 


void operator delete(void* ptr)

{

delete []ptr;

}


참고로 사용하는 컴파일러에서 void 포인터 형 대상의 delete 연산을 허용하지 않는다면, 위의 delete문을 다음과 같이 작성하면 된다.

delete []((char*)adr);



19행; 컴파일러에 의해, 필요한 메모리 공간의 크기가 바이트 단위로 계산되어서 인자로 전달되니, 크기가 1바이트인 char 단위로 메모리 공간을 할당해서 반환한다. 


Point* ptr = new Point(3, 4);


아직 객체생성이 완성된 상태가 아닌데, 어떻게 멤버함수의 호출이 가능했을까?

그것은 operator new 함수와 operator delete 함수가 static 으로 선언된 함수이기 때문이다.

비록 멤버함수의 형태로 선언을 해도 이 둘은 static 함수로 간주가 된다. 그래서 객체생성의 과정에서 호출이 가능했던 것이다.






operator new & operator new[]


new 연산자는 다음 두 가지의 형태로 오버로딩이 가능하다.


void* operator new(size_t size){    }

void* operator new[](size_t  size){    }


두번째 함수는 new 연산자를 이용한 배열할당 시 호출되는 함수이다.

Point* arr  = new Point[3]; 이런 문장을 만나면,

컴파일러는 세 개의 Point객체에 필요한 메모리 공간을 바이트 단위로 계산해서, 이를 인자로 전달하면서 new[] 함수를 호출한다.

즉, 열할당 시 호출되는 함수라는 사실을 제외하고는 operator new 함수와 차이가 없다.


마찬가지로 delete 연산자도 다음 두 가지의 형태로 오버로딩이 가능하다.


void operator delete(void* adr){    }

void operator delete[](void* adr){    }


두 번째 함수는 delete 연산자를 이용한 배열소멸 시 호출되는 함수이다.

delete []arr;


58행:  객체로 구성된 배열이기 때문에 모든 객체의 소멸자가 호출된 다음에 36행에 정의된 멤버함수(static 함수)가 호출된다.



반응형
반응형

Link : http://kldp.org/node/26526

// korText.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>
#include <string>
#include <fstream>

using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
wstring aa = L"abcde 입니다.";
wfstream filestr;

filestr.imbue(locale( "korean" ) ); // 이게 중요
filestr.open (L"C:\test.txt", wfstream::in | wfstream::out | wfstream::app);
filestr.write(aa.c_str(), static_cast<streamsize>(aa.length()));
filestr.close();

return 0;
}

반응형
반응형

http://yamoe.tistory.com/228




RapidXml 1.13 의 샘플





RapidXml : http://rapidxml.sourceforge.net/

Platform
Compiler
strlen()RapidXmlpugixml 0.3pugxmlTinyXml
Pentium 4
MSVC 8.0
2.5
5.4
7.0
61.7
298.8
Pentium 4
gcc 4.1.1
0.8
6.1
9.5
67.0
413.2
Core 2
MSVC 8.0
1.0
4.5
5.0
24.6
154.8
Core 2
gcc 4.1.1
0.6
4.6
5.4
28.3
229.3
Athlon XP
MSVC 8.0
3.1
7.7
8.0
25.5
182.6
Athlon XP
gcc 4.1.1
0.9
8.2
9.2
33.7
265.2
Pentium 3
MSVC 8.0
2.0
6.3
7.0
30.9
211.9
Pentium 3
gcc 4.1.1
1.0
6.7
8.9
35.3
316.0







[test.xml]


<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<root ver="1">
    <entry stop="1">
        <name type="man1">man1</name>
        <content>content1</content>
    </entry>
    <entry step="2">
        <name type="man2">name2</name>
        <content>content2</content>
    </entry>
</root>




[test2.xml]

<?xml version="1.0" encoding="utf-8"?>
<root ver="1">
    <child>child1</child>
</root>




[main.cpp]


#include <string>
#include <vector>
#include <fstream>
#include <iostream>
 
 
#include "rapidxml-1.13\rapidxml.hpp"           // use rapidxml
#include "rapidxml-1.13\rapidxml_print.hpp"     // to wirte file
 
// 노드 출력
void printNode(rapidxml::xml_node<wchar_t>* node)
{
    // print node
    std::wcout << node->name() << L"=" << node->value();
 
    // print attribute
    for( rapidxml::xml_attribute<wchar_t>* attr=node->first_attribute(); attr; attr=attr->next_attribute() )
    {
        std::wcout << L"\t" << attr->name() << L"=" << attr->value();
    }
 
    std::wcout << std::endl;
}
 
// xml 파일 읽기
void ReadXml(std::wstring& filepath)
{
    std::wifstream xmlFile;
    xmlFile.open(filepath.c_str(), std::ios_base::in);
    if (!xmlFile.is_open())
    {
        return;
    }
 
    xmlFile.seekg(0, std::ios::end);    // 마지막 파일 포인터로 이동
    std::wifstream::pos_type size = xmlFile.tellg();        // 파일 크기
    xmlFile.seekg(0);                   // 처음 파일 포인터로 이동
 
    // xml 파일을 vector로 읽음
    std::vector<wchar_t> xmlData((int)size + 1, 0);  
    xmlFile.read(&xmlData.front(), (std::streamsize)size);
    xmlFile.close();
 
    // parsing
    rapidxml::xml_document<wchar_t> doc;
    doc.parse<rapidxml::parse_default>(&xmlData.front());
     
     
    // get root
    rapidxml::xml_node<wchar_t>* root = doc.first_node();
 
    // print root node & attribute
    printNode(root);
 
    // print child node
    for ( rapidxml::xml_node<wchar_t>* item=root->first_node(); item; item=item->next_sibling() )
    {
        printNode(item);
 
        for ( rapidxml::xml_node<wchar_t>* subitem=item->first_node(); subitem; subitem=subitem->next_sibling() )
        {
            printNode(subitem);
        }
         
    }
    doc.clear();
}
 
// xml 파일 저장
void SaveXml(std::wstring& filename)
{
    rapidxml::xml_document<wchar_t> doc;
 
    // append xml declaration
    rapidxml::xml_node<wchar_t>* header = doc.allocate_node(rapidxml::node_declaration);
    header->append_attribute(doc.allocate_attribute(L"version", L"1.0"));
    header->append_attribute(doc.allocate_attribute(L"encoding", L"utf-8"));
    doc.append_node(header);
 
    // append root node
    rapidxml::xml_node<wchar_t>* root = doc.allocate_node(rapidxml::node_element, L"root");
    root->append_attribute(doc.allocate_attribute(L"ver", L"1"));
    doc.append_node(root);
 
    // append child node
    rapidxml::xml_node<wchar_t>* child = doc.allocate_node(rapidxml::node_element, L"child");
    child->value(L"child1");
    root->append_node(child);
 
    std::wstring xmlString;
    rapidxml::print(std::back_inserter(xmlString), doc);
 
    // 문자를 UTF-8로 변환해서 저장해야 하는데
    // 샘플이므로 처리 하지 않아 실제로 ANSI 파일 형식으로 저장됨
    std::wofstream wstream;
    wstream.open(filename.c_str());
    wstream << xmlString;
    wstream.clear();
}
 
int _tmain(int argc, _TCHAR* argv[])
{      
    ReadXml(std::wstring(L"test.xml"));
    SaveXml(std::wstring(L"test2.xml"));
    return 0;
}

반응형
반응형




년도(12) 달, 날짜, 시간, 분,초를 얻는다


// 시간얻기
__time64_t t64;
_time64(&t64);
tm* Tm;
Tm = _localtime64(&t64);
  
WCHAR Path[512];
swprintf( Path, L"%.2d%.2d%.2d %.2d:%.2d:%.2d",
 Tm->tm_year+1900-2000, Tm->tm_mon+1, Tm->tm_mday, Tm->tm_hour, Tm->tm_min, Tm->tm_sec );












블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc..




이건 위내용을 수정한것이며 년도(2012) 달, 날짜, 시간, 분,초를 얻는다




#include <iostream>
#include <string>
using namespace std;
#include <WTypes.h>
#include <time.h>
int main()
{
__time64_t t64;
_time64(&t64);
tm* Tm;
Tm = _localtime64(&t64);

WCHAR Path[512];
swprintf( Path, L"%.2i%.2i%.2i %.2i:%.2i:%.2i", Tm->tm_year+1900, Tm->tm_mon+1, Tm->tm_mday, Tm->tm_hour, Tm->tm_min, Tm->tm_sec );


return 0;
}

반응형
반응형

http://blog.naver.com/elastica/50045305787




윈도우즈 프로그램을 개발하다 보면 날짜 및 시간 관련 처리가 필요한 경우가 많습니다.

특정 날짜 기준으로 어느 시간이 경과한 이후에 로그 파일을 지운다거나

특정 날짜에 프로그램을 실행 시킨다거나 또는 두 시간 사이의 차이점을 알아보고자 할때도

있구요..  다양한 요구 사항이 나올 수 있습니다.

 

위와 같은 요구사항에 적용될 수 있는 시간 및 날짜 관련 Tip 에 대해 정리해 보았습니다. 

1> 현재 시간 알아오기

 

아래의 두가지 코드 예제를 보시기 바랍니다.

 

첫번째 CTime::GetCurrentTime() 이 현재의 정확한 시간을 가지고 오는 함수 입니다.

CTime now1 = CTime::GetCurrentTime(); (O)

 

아래에 사용된 GetCurrentTime API 는 GetTickCount 로 대체 되었으며

시스템이 시작된 이후 경과돤 시간을 밀리세컨드로 리턴해 주는 함수입니다.

CTime now2  = GetCurrentTime(); (X)

 

CString 의 Format 을 통해 좀더 자세히 알아보겠습니다.

지금 시간이 3월 4일 오후 16:23 분 경입니다.

 

CTime::GetCurrentTime 을 사용했을 경우 정확한 현재 시간을 가져옴을 볼 수 있습니다.

 

 

*예제코드

CTime now1 = CTime::GetCurrentTime();

CTime now2  = GetCurrentTime();

 
 CString strTime1;
 
 strTime1.Format(_T("%04d-%02d-%02d %02d:%02d:%02d"),now1.GetYear(), now1.GetMonth(),now1.GetDay(),now1.GetHour(), now1.GetMinute(),now1.GetSecond());

 

 CString strTime2;

 strTime2.Format(_T("%04d-%02d-%02d %02d:%02d:%02d"),now2.GetYear(), now2.GetMonth(),now2.GetDay(),now2.GetHour(), now2.GetMinute(),now2.GetSecond());


 

2> 현재 시간 기준으로  특정 기간 전후 시간 알아오기

 

CTimeSpan  이란 클래스가 있습니다.

CTimeSpan( ) throw( );
CTimeSpan(
   __time64_t time 
) throw( );
CTimeSpan(
   LONG lDays,
   int nHours,
   int nMins,
   int nSecs 
) throw( );

 

CTimeSpan span(1,0,0,0); // 하루의 시간 간격을 의미합니다.

CTimeSpan span(0,1,0,0); // 한시간의 시간 간격을 의미합니다.

CTimeSpan span(0,0,1,0); // 1분의 시간 간격을 의미합니다.

CTimeSpan span(0,0,0,1); // 1초의 시간 간격을 의미합니다.

 

현재 시간 기준으로 하루 이후의 시간을 알고 싶은 경우 아래와 같이 코드를 작성합니다.

 

CTime now1 = CTime::GetCurrentTime();

 CTimeSpan span(1,0,0,0);

 CTime tomorrow = now1 + span;

 
 CString strTime1;
  
 strTime1.Format(_T("%04d-%02d-%02d %02d:%02d:%02d"),tomorrow.GetYear(), tomorrow.GetMonth(),tomorrow.GetDay(),
  tomorrow.GetHour(), tomorrow.GetMinute(),tomorrow.GetSecond() );

 

현재 시간은 4월 3일 16:33 분 경입니다. 정확하게 하루 이후의 날짜와 시간을 가지고 오는 것을

확인 하실 수 있습니다.

 

만약 하루 이전의 시간을 가지고 오고 싶으면 CTime tomorrow = now1  - span; 로 수정하시면 되겠죠.

 

시간 계산에 있어  범하기 쉬운 오류가 있습니다.

아래의 코드를 보시기 바랍니다.

 

CTime curTime = CTime::GetCurrentTime();
 // 스케쥴 실행시간
 CTime schTime(curTime.GetYear(), curTime.GetMonth(), curTime.GetDay() + 1, 0, 0, 0);
 CTimeSpan resultTime = schTime - curTime;

언뜻보면 문제가 없어 보이지만 curTime.GetDay() + 1 에서 에러가  발생한 가능성이 있습니다.

 

CTime 클래스의 생성자는 다음과 같습니다.

 

CTime(
   int nYear,
   int nMonth,
   int nDay,
   int nHour,
   int nMin,
   int nSec,
      int nDST = -1 
);

즉 세번째 인자는 Day 로써 최고 31까지 값이 있습니다.

 

그런데 만약 31일에 위의 코드를 실행하면 curTime.GetDay() + 1  = 32 가 되므로 예외가 발생하게

됩니다.

 

3>두 시간의 간격을 알아오는 방법

 아쉽게도 CTime 클래스는 최소 단위가 초(Second) 까지 입니다.

따라서 좀더 정밀한 시간 비교를 위해서는 적합하지가 않습니다.

 

초단위까지 동일하더라도 실제 두시간 사이에는 밀리 세컨드 단위로 차이가 나게 되어 있습니다.

이런 경우 각 시간의 간격(Gap) 을 가져오는 방법입니다.

 

FILETIME 이란 구조체가 있습니다.

 

정의는 아래와 같습니다.

typedef struct _FILETIME {
   DWORD dwLowDateTime;   /* low 32 bits  */
   DWORD dwHighDateTime;  /* high 32 bits */
} FILETIME, *PFILETIME, *LPFILETIME;

 

상위 32 비트  하위 32비트 즉 64비트 수준까지 데이터를 담을수 있는 구조입니다.

 

SYSTEMTIME 으로 설정된 시간을 FILETIME 으로 변경하는 API 로 SystemTimeToFileTime 라는 것이 있습니다.

SystemTime 을 FileTime 으로 변경시키는 함수 입니다.

 

BOOL WINAPI SystemTimeToFileTime(
  __in   const SYSTEMTIME *lpSystemTime,
  __out  LPFILETIME lpFileTime
);

아래 예제를 보시기 바랍니다.

 

 

시작 시간과 종료 시간이 절대적으로 동일하지만 않다면 두 시간 사이의 간격을

밀리 세컨드(ullDif ) 단위와 초(TimeInterval) 단위로 알아 볼수가 있습니다.

 

 SYSTEMTIME StartTime,EndTime;
  
 GetLocalTime(&StartTime);;//시작 시간

 Sleep(1000);

/* 두시간이 밀리세컨드 단위까지 동일하지 않아야 함 */

 GetLocalTime(&EndTime);;//종료시간
 
 FILETIME fTm1, fTm2;

 ULONGLONG *ullVal1, *ullVal2;
 ULONGLONG ullDif;
 float TimeInterval;
 SystemTimeToFileTime(&StartTime, &fTm1);
 SystemTimeToFileTime(&EndTime, &fTm2);

 
 ullVal1 = (ULONGLONG *)&fTm1;
 ullVal2 = (ULONGLONG *)&fTm2;

 ullDif = *ullVal2 - *ullVal1;  //100 나노 세컨드 단위

 TimeInterval = float(ullDif /10000) /1000; //다운받은 간격 초단위로 

 

4>특정 시간 이후 타이머 설정하는 방법

현재 시간 기준으로 특정 시점에 특정 작업을 실행할 필요성이

있는 경우가 있습니다.

예약 시스템이나 알람 시스템에서 사용이 될거 같네요.

두가지 예제 입니다.

 

*현재 시간 기준으로 얼마 이후에 실행하는 방법

 

CTime now = CTime::GetCurrentTime(); //현재시간
 CTime startTime;

 //오늘 기준 시작 시간에서 1일 1시간 1분 1초 후에 타이머를 실행하고 싶은 경우
 CTimeSpan sp(1,1,1,1);  
  
 startTime  = now + sp;
 CTimeSpan GapTime = startTime - now;
 
 int intTotalSeconds1 = (int)GapTime.GetTotalSeconds();

 //타이머는 밀리세컨드 단위이므로 1000을 곱해야 함
 SetTimer(0,intTotalSeconds1*1000,NULL);  

*특정 날짜에 실행하고 싶은 경우 

 

 //특정날짜에 실행하고 싶은 경우 아래 코드는 4월 10일 0:0:0 기준
 CTime startTime1(now.GetYear(), now.GetMonth(), 10, 0,0,0);

 GapTime = startTime1 - now;

 

 int intTotalSeconds2 = (int)GapTime.GetTotalSeconds();

 //타이머는 밀리세컨드 단위이므로 1000을 곱해야 함
 SetTimer(1,intTotalSeconds2*1000,NULL);  

 

반응형
반응형

http://www.gisdeveloper.co.kr/499




[C++] XML 파서, CMarkup 

XML 데이터를 쓰고 읽기 위해서 인터넷을 검색하던 차에 속도를 강점으로 내세우면서 STL 만을 사용하여 플랫폼 이식에도 뛰어난 오픈소스를 찾았는데요. 바로 CMarkup 입니다. 다운로드 사이트는 http://www.firstobject.com/ 이구요. 사용해 보니 XML의 charset도 지원하여 더욱 믿음이 가는 오픈소스였습니다. XML을 처리할 일이 있다면 한번 사용해 보시기 바랍니다.

추후 이 오픈소스를 다시 사용할 때를 대비하여 사용 방법을 정리해 정리차원에서 올려봅니다.

컴파일 시 주의할 사항은... CMarkup은 MFC의 CString와 STL의 string에 대한 문자열 타입을 사용하며 기본적으로 CString을 사용합니다. 플랫폼에 독립적인 구성을 위해서 STL을 사용하는것이 좋기 때문에 전처리에서 MARKUP_STL를 정의해줘야 합니다. 이 전처리 정의는 프로젝트의 속성 페이지에서 해줌으로써 전역적으로 적용되도록 해야 합니다. 아래의 코드는 XML을 쓰는 예제 코드입니다. 윈도우즈 계열의 개발툴인 VS2008로 작성했습니다.




#include "stdafx.h"

#include "../Markup.h"


int _tmain(int argc, _TCHAR* argv[])

{

    CMarkup xml;


    xml.AddElem( "ORDER" );

    xml.AddChildElem( "ITEM" );

    xml.IntoElem();

    xml.AddAttrib("type", "A");

    xml.AddChildElem( "SN", "132487A-J" );

    xml.AddChildElem( "NAME", "crank casing" );

    xml.AddChildElem( "QTY", "1" );

    xml.OutOfElem();


    xml.AddChildElem( "ITEM" );

    xml.IntoElem();

    xml.AddAttrib("type", "C");

    xml.AddChildElem( "SN", "434417F-Y" );

    xml.AddChildElem( "NAME", "kully casing" );

    xml.AddChildElem( "QTY", "2" );

    xml.OutOfElem();


    std::string csXML = xml.GetDoc();


    printf("%s", csXML.c_str());


    return 0;

}


결과는 다음과 같습니다.

사용자 삽입 이미지

AddElement를 통해 엘리먼트를 만들고, 해당 엘리먼트의 자식을 추가하기 위해 AddChildElem을 사용하거나 먼저 IntoElem을 호출한 후 다시 AddElement를 사용합니다.

이제 반대로 위와 같은 XML 데이터를 읽어 보도록 하겠습니다. 먼저 위의 결과를 파일로 저장해 놓고 그 파일을 읽어 데이터를 추출하는 예제를 들어 보겠습니다. 예를 들어... 아이템(ITEM)의 이름(NAME)과 수량(QTY)을 읽어 보도록 하겠습니다. 위의 XML 문자열의 경우 아이템의 개수는 총2개이므로 2개가 검색될 것입니다. 다음이 이 예제와 부합되는 코드입니다.




CMarkup xml;
xml.Load("d:/data.xml");

while ( xml.FindChildElem("ITEM") )
{
    xml.IntoElem();

    xml.FindChildElem( "NAME" );
    std::string csSN = xml.GetChildData();
    xml.FindChildElem( "QTY" );
    int nQty = atoi(xml.GetChildData().c_str());

    xml.OutOfElem();

    printf("%s, %d\n", csSN.c_str(), nQty);
}



먼저 XML 데이터를 가지고 있는 파일을 Load 매서드를 이용해 읽습니다. 다시 반복문을 사용하여 루트 엘리먼트의 자식 ITEM 엘리먼트를 검색하기 위해 FindChildElem을 사용합니다. 그러면 해당되는 자식 엘리먼트가 추출됩니다. 해당되는 자식 엘리먼트의 자식 엘리먼트를 읽기 위해 IntoElem() 함수를 사용한 뒤에 원하는 엘리먼트(NAME, QTY)를 검색하기 위해 FindChildElem을 호출하고 실제로 값을 읽기 위해서 GetChildData 매서드를 호출합니다. 다 읽은 후 OutOfElem()을 호출합니다. 결과는 아래와 같습니다.

사용자 삽입 이미지







 Commented by 산비둘기 at 2009/11/16 12:09  r x
바쁜업무에 시간내서 글들 정리 하시느라 수고가 많으십니다 . 
좋은 정보 얻고 갑니다 . ^^ 
Replied by 김형준 at 2009/11/16 22:55 x
산비둘기님, 별 말씀을요. 제 스스로에게도 큰 도움이 되고 있습니다.
 Commented by DarkKiss at 2010/01/04 16:13  r x
xml parser에 관한 정보를 찾다가 오게되었네요 좋은 정보 얻어갑니다^^ CMarkup 이용해서 xml에서 정보 가져오는 부분 구현해 봐야 겠네요^^ 그럼 새해 복 많이 받으시고 행복한 하루 하루 보내세요^^ 
Replied by 김형준 at 2010/01/04 17:02 x
네, 이 글이 도움이 되시면 좋겠습니다. 새해 복 많이 받으세요~
 Commented by 나무 at 2010/04/24 09:13  r x
좋은 정보 감사합니다...^^ 
Replied by 김형준 at 2010/04/26 15:59 x
댓글 감사드립니다.
 Commented by JHoney at 2010/06/15 23:38  r x
감사합니다 정말 좋은 정보네요 ^-^ 
Replied by 김형준 at 2010/06/16 18:59 x
저 역시 지금도 잘 활용하고 있는 xml 처리 라이브러리입니다. 도움되셨다니 저도 좋네요!
 Commented by 미아 at 2010/07/06 01:06  r x
xml 파싱으로 검색하다가 들어왔습니다.
덕분에 생각보다 쉽게 문제를 해결했어요. 
좋은 정보 감사합니다~~^_^ 
Replied by 김형준 at 2010/07/07 10:16 x
네, 도움되셨다니 좋습니다!
 Commented by 울티 at 2010/08/16 18:30  r x
안녕하세요 해당 강좌를 보고 조금 어설프게라도 따라했는데 잘 되지 않는 부분이 있어서 문의드려요~ 간단하게 작성했는데.. 실행결과는 아무것도 나오질 않네요 ㅠㅠ
CMarkup xml;

xml.AddElem(MCD_T("Test"));
xml.AddChildElem(MCD_T("a"));
xml.IntoElem();
xml.AddAttrib(MCD_T("type"),MCD_T("a"));
xml.AddChildElem(MCD_T("sss"),MCD_T("2344"));
xml.OutOfElem();

std::wstring csXML = xml.GetDoc();

printf("%s",csXML.c_str());

이게 전부인데 아무런 결과가 나오지 않네요; 
아 그리고 저는 문자열 앞에 MCD_T 이걸 꼭 써야 하던데 안쓰면 에러가나더라구요 
어떻게 해야 그냥" " 이런식으로 사용할 수 있나요 ? 
Replied by 김형준 at 2010/08/18 18:42 x
글쎄요.. MCD_T 매크로를 사용은 처음봅니다만.. 프로젝트 속성 중 사용하는 캐릭터를 멀티바이트 모드로 하면.. 단순히 ".." 만으로 될테고.. 유니코드라면.. L".."인가.. 아니면 T".."인가로 하면 될텐데요..
 Commented by 나쁜남자 at 2010/08/20 18:11  r x
많은 도움이 됐습니다. 
Replied by 김형준(Dip2K) at 2010/08/20 18:31 x
댓글, 감사합니다!
 Commented by 굳굳 at 2010/11/07 22:21  r x
정말 간단하군요 ^^ 
Replied by 김형준 at 2010/11/08 21:27 x
도움이 되셨길 바랍니다!
 Commented by 빵집상인 at 2010/11/13 20:56  r x
올ㅋ 유용한데요~?
Load메서드로 로드하려면 *.xml파일만 읽어들일수있는겐가요? 
Replied by 김형준 at 2010/11/16 15:14 x
파일 확장자는 큰 의미가 없고.. 파일 내용이 xml 포맷이면 됩니다.
 Commented by 김진 at 2010/12/08 17:54  r x
각 함수인자가 유니코드로 되어 변환 에러(error C2664)가 나오는데 이는 어떻게 해결해야 할까요? L 붙이면 printf 에서 에러가 발생하는데;;ㄷㄷ 
Replied by 김형준(Dip2K) at 2010/12/09 22:36 x
유니코드 문자에 함수가 따로 존재합니다.. printf인 경우 wprintf 문을 사용하셔야 합니다..
 Commented by 이효진 at 2011/01/05 10:17  r x
XML 검색하다 찾아왔습니다. 좋은 정보 감사합니다 ^^ 종종 찾아오게 될거 같아요 ㅎㅎ 
Replied by 김형준 at 2011/01/05 19:34 x
도움이 되셨다니 저도 기분이 좋습니다. ^^
 Commented by 안병규 at 2011/04/04 13:31  r x
혹시 라이센스 문제는 어떻게 되는건지 알수 있을까요??
CMarkup Parser 파일안에 들어있는 evaluationlicense.txt 이것 읽어봐도 잘 이해가 안가네요;;; 
Replied by 김형준 at 2011/04/06 17:11 x
상용버전에 사용하려면 구입하라는 의미인듯한데요..
 Commented by 한창영 at 2011/04/13 10:28  r x
CMarkup은 push-pop 구조라서 프로그래밍하기가 수월해서 좋더군요. 다만, 제가 필요하던 주요기능들은 모두 사용버젼에서만 지원하더라구요. 여하튼 주어진 함수들로 필요한 기능은 구현했는데 한가지 아쉬운 것은 indentation 기능이었습니다. 그래서, 다음과 같이 다른 클래스를 사용해서 저장만 하고 있습니다. 참조하세요.
CXml myXML;
myXML.LoadXml( (LPCTSTR) m_strXML );
myXML.SaveWithFormatted(lpszPathName, _T("UTF-8") ); ///default is UTF-8
myXML.Close(); 



반응형
반응형

http://blog.naver.com/patori/90033021950




 

그동안 미뤘던 애니메이션 공부를 다시 하게 됐다.

 

DirectX에서 지원하는 함수로 X파일을 그냥 로드하려고 했는데,

예제 Sample이 훨 어렵다. MS사에서 진정 이걸보고 예제로 쓰라는건지가 의심스럽다.. 

 

어쨌든 일단 예전에 봤던 김용준님의 저서 3D 게임 프로그래밍에서 봤던 xml부터 다시 공부하기로 했다.

xml 코드가 보기도 쉽고 체계적으로 잘 되어 있어서 포맷 공부하기엔 딱인듯 하다.

나중에 MaxScript를 만질 기회가 생긴다면 포맷도 새로 만들수도 있겠다. (먼산) 

 

------------------------------------------------------------------------------------------------------

 

<Body>에서 <Info>, <Material>, <Object>로 크게 갈라진다.

<Info>: 최초로 읽어 들일 때, 전체적으로 가지고 있는 기본 정보가 들어있다.

<Material>: 메터리얼 정보를 가지고 있다.

<Object>: 메쉬와 본, 바이패드 등의 상세 정보를 담고 있다.

 

 

<Info>

 

일단 Info의 정보를 살펴보면 위에서부터 차례대로,

파일이름, 오브젝트 수, 메쉬 수, 애니메이션 프레임 크기, 키 타입, <Object>, <Bone>이 있다.

여기서 오브젝트 수는 <Object>의 총 개수이겠거니 했는데, 정확히 맞지 않는다.

나중에 파싱할 때 이부분은 다시 교체한다.

<info>에서  접혀진 부분에는 이런 값이 들어있다.

 

 

<Bone>에서 BoneID와 ID가 있는데 BonID는 뼈대 개수만큼 있고,

ID는 해당 본의 실제 Object ID를 말한다.

위의 그림에서  BoneID가 1인 Bip01은 Object ID가 7이라는 것을 알 수 있다.

 

여기까지가 <info> 부분이다.

 

 

<Material>

 

메터리얼은 텍스쳐, 광원 등의 재질 정보다.

 

 

<Material>의 개수는 <Slot>의 Index 최종값+1이다.

<Slot>안에서 Material에 대한 정보를 기록한다.

<Diffuse><Ambient><Specular><Emissive><Opacity><Power>는 필수 정보이고,

그 이후의 <DiffuseMap><NormalMap><BumpMap>은 사용된 텍스쳐 종류에 따라 추가된다.

 

 

<Object>

 

가장 데이터 양이 많은 Object부분이다.

해당 Object에 해당하는 모든 정보를 저장하고 있다.

 

 

일단 여기서 Class를 유심히 보아야 한다. 이 Class는 3ds Max에서 이미 정해진 클래스이다.

Class의 종류는 4가지 이다.

 

 

 

Dummy : 더미 클래스로  아무 일도 안하지만, 바운딩 박스와, 위치 정보를 가지고 있다.

              계층적으로 본과 바이패드를 분리할 때, 각각의 계층을 대표하는 정보를 가지고 있다.

Editable_mesh : 메쉬에 해당하는 부분으로 메쉬를 표현하기 위한 모든 정보가 들어있다.

 

Dummy + Editable_mesh 수가 <Info>의 MeshCount 수와 같다.

 

BoneGeometry : Bone에 대한 정보를 가지고 있다.

Biped_Object : 바이패드 정보를 가지고 있다.

이 두 클래스는 상당히 유사하다.

 

클래스별로 세부 내용이 다르고, 그 중 Editable_mesh 와 BonGeometry & Biped_Object 로 크게 분류할 수 있다.

 

Editable_mesh

 

 

여러 섹션중에 가장 많은 정보를 담고 있다.

Parent, Local, World, BoundingBox는 4클래스 모두 공통으로 가지고 있다.

Parent는 계층분류에 사용되고 Editable_mesh에서는 -1(부모를 소유하지 않음)로 설정된다.

그 아래 부분부터가 Editable_mesh의 고유 영역이다.

 

<Vertex> : 버텍스 좌표를 담고 있다.

 

<VertexNormal> : 법선 벡터

 

<TriIndex> : 삼각형 Index 정보를 가지고 있고, index 번호는

                 <Vertex> 안에서 지정된 Index가 사용된다.

 

하나의 메쉬 안에서 여러개의 Material을 설정할 수 있다.

TriIndex의 MaterialCount는 Material의 개수를 담고 있는데,

나중에 파싱할 때에는 하나의 메쉬에 하나의 재질만 가질 수 있도록 분할하는 작업을 하게 된다.

그래야지 나중에 출력 루프가 간편해진다.

일단 여기서는 해당 2번 재질이 사용된 것을 알 수 있다.

 

<TexVertex> : 인덱스 u,v 좌표를 담고 있다.

<TexIndex>  : <TriIndex>와 비슷한 형식으로 대신 TexVertex에서 지정한 인덱스를 기준으로 지정된다.

 

<VertexWeight> : 스키닝에 필요한 각각의 정점 가중치를 지정한다.

 

BoneCount는 해당 Mesh가 스키닝을 위해 참조하는 뼈대의 개수를 저장하고

Vertex를 Index순으로 차례대로 나열하면서 관련된 뼈대의 ID와 가중치를 저장한다. 

 

 

하나의 Vertex당 뼈대는 최대 4개까지 지정할 수 있다.

나중에 계산을 할 때

VResult = VLocal * ( MSkinning0 * MWeight0 + ... + MSkinning3 * MWeight3)  

이런 식으로 계산을 하게 되는데, 관련된 뼈대 개수가 많아지면 행렬 연산이 상당히 많아지므로

최대 4개까지로 지정해 두었다. Bone에서 MSkinning을 구하는 과정까지의 행렬계산 부분도 많기 때문에

어쩔수 없다.

(팔레트 테이블을 사용하거나 버텍스 셰이더를 사용하면 GPU에서 계산을 처리하게 되서 속도를 향상시킬 수 있다.)

 

가중치는 합이 1.0이 되고, 필요에 따라서는 클 수도 있다.

 

BonGeometry & Biped_Object

 

본과 바이패드는 애니메이션에 관한 정보를 담고 있다.

 

 

부모 ID에서 상위 계층 ID를 지정하게되고 나중에 Animation 변환 행렬을 설정할 때

부모의 최종 변환 행렬을 곱해서 최종 Animation 변환 행렬을 구할 수 있다.

 

<Key>안에는 3가지 섹션이 있다.

 

<Position> : 지정된 프레임의 순간 위치 좌표가 설정된다.

 

<Quaternion> : 프레임당 회전량을 쿼터니온으로 표현하였다.

                      쿼터니온은 이전에 기록된 프레임(5frame경우는 0frame)이후의 상대값으로

                      저장되기 때문에 파싱후에는 차례대로 누적을 해서 값을 갱신시켜줘야 한다.

 

<Scale > : 확대/ 축소 비율을 나타낸다.

 

 

------------------------------------------------------------------------------------------------------

 

이렇게해서 기본적인 xml분석은 오와리!

 

반응형

+ Recent posts