#pragma는

- 각각의 컴파일마다 독립적인 기능을 제공하기 위하여 이용(다른 컴파일에서는 처리 안 될 수 있음)
- VC++에서는 많은 pragma directives가 있음(alloc_text, auto_inline, bss_seg, check_stack, code_seg, comment, component, conform, const_seg, data_seg, deprecated, function, hdrstop, include_alias, init_seg, inline_depth, inline_recursion, intrinsic, managed, message, once, optimize, pack, pointers_to_members, pop_macro, push_macro, runtime_checks, section, setlocale, unmanaged, vtordisp, warning)
- 정의 안 된 pragma directives를 사용하면 단순히 경고(warning C4068: unknown pragma)만 output 창에 출력하고, 무시됨
- 많이 사용하는 것 몇 가지만 앞으로 살펴볼 것임
- 이번시간에는 once, warning

1.#pragma once
이는 중복 include하는 것을 막는 것이다.
만일 중복 include가 되면, error C2011: 'CA' : 'class' type redefinition

#ifndef _A_H_
#define _A_H_
class CA {
...
}
#endif
와 

#pragma once
class CA {
...
}
는 동일한 것이다.

VC++에서 자동으로 class를 만들면 
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
라는 코드가 삽입되어 있는데, 이는 #pragma once가 VC++버전이 1000이상인 곳에서만 의미가 있기 때문이다.(Visual C++ 5.0 => 1100, Visual C++ 6.0 => 1200, Visual C++ .NET 2003 => 1310, Visual C++ 2005 => 1400)

2.#pragma warning(disable : 4244; once : 4101; error : 4700)
소스를 컴파일하면 error와 warning이 나타나는데, warning의 경고수준을 결정하는 것임
거의 쓸 일은 없지만, 재미로 한번 살펴보기만 하자.

void main() {
    double f;
    int k1, k2;
    int n=f;
}
이를 컴파일하면 output창에 아래의 warning이 나타난다.
warning C4244: 'initializing' : conversion from 'double' to 'int', possible loss of data
warning C4101: 'k1' : unreferenced local variable
warning C4101: 'k2' : unreferenced local variable
warning C4700: local variable 'f' used without having been initialized
0 error(s), 4 warning(s)

이때 disable은 해당 warning이 output창에 나오지 않도록 무시하라는 지정
once는 동일한 warning에 대해 한번만 나오라는 것
error는 해당 warning을 error로 취급하라는 것이다.

#pragma warning(disable: 4244)
#pragma warning(once: 4101)
#pragma warning(error: 4700)
void main() {
    double f;
    int k1, k2;
    int n=f;
}
을 컴파일하면
warning C4101: 'k1' : unreferenced local variable
error C4700: local variable 'f' used without having been initialized
1 error(s), 1 warning(s)
가 나오는 것을 알 수 있다.

하지만 warning을 소홀히 하는 것은 매우 좋지 않은 습관이다. 
warning도 꼭꼭 해결하고 넘어가도록 하자. 
void main() {
    double f=0.;
    int n=(int)f;


VC 단축키 및 주석 매크로
 

[VC] 단축키

Ctrl + Tab  Edit하고 있는 Child Window 간의 이동  
Ctrl + F4    현재 Edit하고 있는 Child Window를 닫기  
Ctrl + I      문자열 입력 점진적으로 문자열 찾기 (Incremental Search)  
Ctrl + F3    현재 커서에 있는 문자열 찾기 fowared (블록 지정 안 해도 됨)  
Shift + F3   현재 커서에 있는 문자열 찾기 backward  
F3            찾은 문자열에 대한 다음 문자열로 이동 (Next Search)  
Ctrl + H     문자열 찾아 바꾸기 (Replace)  
Ctrl + Left/Right Arrow  단어 단위로 이동  
Ctrl + Delete 또는 Backspace  단어 단위로 삭제  
Ctrl + F2    현재 라인에 북마크 지정/해제  
F2            지정된 다음 북마크로 이동  
Ctrl + Shift + F2  지정된 모든 북마크를 해제  
F9            현재 라인에 Breakpoint를 지정/해제  
Ctrl + Shift + F9  현재 Edit하고 있는 소스파일에 지정된 모든 Breakpoint 해제  
Ctrl + ] 또는 E  '{'괄호의 짝을 찾아줌 ('{'에 커서를 놓고 눌러야 함}  
Ctrl + J, K  #ifdef 와 #endif의 짝을 찾아줌  
Ctrl + L  한 라인을 클립보드로 잘라내기 (Cut)  
Ctrl + Shift + L  한 라인을 삭제  
Alt + Mouse  블록 설정 세로로 블록 설정하기 (마우스로)  
Ctrl + Shift + F8  세로로 블록 설정하기 (키보드로), 취소할 때는 Esc키를 눌러야 함  
블록 설정 -> Tab  선택된 블록의 문자열을 일괄적으로 들여쓰기(Tab) 적용  
블록 설정 -> Shift + Tab  선택된 블록의 문자열을 일괄적으로 내어쓰기 적용  
Alt + F8 -> Tab 또는 Shift + Tab  들여쓰기 자동 조정 (Tab:들여쓰기, Shift + Tab : 내어쓰기)  
Ctrl + T  현재 커서에 있는 변수/함수에 대한 Type이 Tooltip 힌트 창에 나타남  
Ctrl + Alt + T  멤버 변수/함수 목록에 대한 팝업 창이 나타남  
Ctrl + Shift + T  공백/콤마/파이프/괄호 등을 기준으로 좌우 문자열을 Swap시킴  
Ctrl + Shift + 8  문단기호 표시/감추기 : Tab은 ^, Space는 .으로 표시  
Ctrl + D  툴바의 찾기 Editbox로 이동  
Ctrl + Up/Down Arrow  커서는 고정시키고 화면만 스크롤 시키기  
Tab 들여쓰기
Shift+Tab 내어쓰기
F4 다음 에러메세지로 이동
Alt+F8 들여쓰기 자동 조정
Ctrl+F 찾기
Ctrl+F3 현재 커서에 있는 단어로 찾기
Ctrl+H 찾아 바꾸기
F3 다음 단어 찾기
Ctrl+Shift+F3 이전 단어 찾기
Alt+E+I 프로젝트 내의 모든 파일에서 찾기
F2 설정된 북마크로 이동
F9 현재 커서위치에 BreakPoint를 설정/해제
Ctrl+B 브레이크 포인트 관리 메뉴
Ctrl+Spacebar 멤버목록 팝업창
Ctrl+T 현재 커서에 있는 단어의 툴팁정보 보기
Ctrl+U 모두 소문자로
Ctrl+Shift+U 모두 대문자로
Ctrl+Shift+8 Tab은 ^ 로 공백은 . 으로 보여줌

디버깅에 관련된 단축키 하나 더. 
변수이름을 적어 놓고 브래이크 포인터의 위치 여부와 관계 없이 변수의 내용을 추적하는 기능이 Watch Window에 들어 있다. 디버그 모드에서 추가하고픈 변수나 등등 앞에 커서를 위치 시킨후 Shift + F9를 누르면 그냥 바로 추가된다.  

▼ Browse Information file 이 필요한 단축키(컴파일 되어야 함)

F12 현재 커서의 함수 정의 부분으로 이동

Shift+F12 현재 커서의 함수 참조 부분으로 이동

Ctrl+Num+ 다음 정의/참조 로 이동

Ctrl+Num- 이전 정의/참조 로 이동


▼ Visual Assist 6.0 설치시 가능한 단축키

Alt+O 현재 파일의 헤더(.h)/구현(.cpp) 파일로 이동

Alt+G 현재 커서의 함수 정의 부분으로 이동

Alt+M 현재 파일의 모든 함수 목록

Ctrl+Shift+V 선택해서 붙여넣기

Alt+← 이전 커서 위치로 이동

Alt+→ 다음 커서 위치로 이동

VC++에서의 단축키

Ref: Visual Studio Help 

우선 닷넷 단축키 설정을 vc++ 6으로 변경(도구 -> 옵션 -> 환경 -> 키보드 )

 
■ 디버그 단축키

변수이름을 적어 놓고 브래이크 포인터의 위치 여부와 관계 없이 변수의 내용을 
추적하는 기능이 Watch Window에 들어 있죠...
그 때 디버그 모드에서 추가하고픈 변수나 등등 앞에 커서를 위치 시킨후
Shift + F9를 누르면 그냥 바로 추가됩니다

■ 주석 매크로.. 

다른 툴도 마찬가지 이지만 VC++로 코딩 하다보면...
지우기는 애매하고, 그냥 두자니 Assert fail 나고 해서 주석 처리 해두고 지나가는
경우가 많습니다.
주석 처리할 코드가 한두 라인일 경우엔 간단하지만
여러 라인일 경우 // 로 처리하자니 너무 많아서 /* */를 쓰게 되는데...
별루 안 이쁘죠. 그리고 주석을 삭제할 때 많이 귀찮고...

자 이제 본론으로 들어가서 주석 처리용 매크로를 정해두고 쓰는 법을 갈쳐 드리겠습니다.

먼저 메뉴의 "Tools/Macro..."를 선택 합니다.
"Macro"라는 이름의 대화 상자가 뜨죠?
"Edit"를 누릅니다. 매크로 이름에 Comment라고 쓰시고 Description은 암꺼나 쓰던지
아님 비워 두시던지...
자 MYMACROS.DSM이란 파일이 뜨죠?

아래와 같이 코드를 복사해 넣습니다.

Sub Comment()
'DESCRIPTION: A description was not provided.

  Dim win
  set win = ActiveWindow
  if win.type <> "Text" Then
  MsgBox "This macro can only be run when a text editor window is active."
  else
  if InStr( ActiveDocument.Selection, vbCr ) > 0 then
  ActiveDocument.Selection.ReplaceText "^", "//", dsMatchRegExp
  Else
  ActiveDocument.Selection = "// " + ActiveDocument.Selection
  End If
  End If

End Sub

자 이제 창을 닫으세요. 저장하라면 "예"를 살포시 눌러 주시구...

다시 메뉴의 "Tools/Macro..."를 선택 해서 "Macro" 대화 상자를 엽니다.
다시 한번 "Edit"를 누릅니다. 매크로 이름에 Uncomment라고 쓰시고...
자 다시 MYMACROS.DSM이란 파일이 뜨죠?

아래의 코드를 또 복사해 넣습니다.

Sub UnComment()
'DESCRIPTION: A description was not provided.

  Dim win
  set win = ActiveWindow
  if win.type <> "Text" Then
  MsgBox "This macro can only be run when a text editor window is active."
  else
  ActiveDocument.Selection.ReplaceText "^//", "", dsMatchRegExp
  End If

End Sub

이제 창을 닫으시고... 저장 하시고...

마지막으로 메뉴의 "Tools/Macro..."를 선택 해서 "Macro" 대화 상자를 엽니다.
"Options >>" 버튼을 눌러서 추가된 버튼 중
"Keystrokes"를 누릅니다.

"Customize" 대화 상자가 열리죠?
거기서 "Macros/Comment"를 선택하고, "Press New Shortcut"을 선택한 다음
"Ctrl + /"를 눌러 줍니다. 입력창에 표시가 되죠?
이제 "Assign" 버튼을 눌러 입력을 종료하고...

다시 "Macros/Uncomment"를 선택하고, "Press New Shortcut"을 선택한 다음
"Ctrl + Shift + /"를 눌러 줍니다. 입력창에 표시를 확인 하신 후
"Assign" 버튼을 눌러 입력을 종료하고...

자 이제 모든 설정이 끝났습니다.
주석 처리를 하고 싶으신 부분을 선택하신 후 "Ctrl + /" 키를 누르면
선택된 라인 전체가 //로 주석 처리 될겁니다.
주석 처리된 라인을 선택한 후 "Ctrl + Shift + /"를 누르면
// 주석 처리가 사라지죠.

잘 활용 하시길... 


0. 미리 알아야 할 용어들

 

플러그인을 만들다 보면 생소한 용어들에 부딛히게 됩니다. 물론 플러그인을 제작하기 위해서는 맥스에 대해서 알아야 하는 게 기본이긴 하지만 혹시라도 그렇지 못한 분들을 위해서 간단하게 기본 용어를 설명하도록 하겠습니다.

 

커맨드 패널(Command Pannel)

 

아래의 스샷은 맥스의 우측에 있는 폼뷰를 캡춰한 것입니다. 이 폼뷰 전체가 커맨드 패널인데요, 제일 위에 있는 탭 중 어떤 것이 선택되어 있느냐에 따라서 그 이름이 다릅니다. 커맨드 패널은 PropertySheet 이고 각 탭을 선택한 것은 Page 정도로 생각하면 되겠습니다. 생긴 것도 그와 유사하게 생겼죠? 아마도 내부 구현도 Tab 혹은 PropertySheet 를 이용했으리라 봅니다.

 

어쨌든 왼쪽에서 오른쪽 순으로 Create Pannel, Modify Pannel, Hierarchy Pannel, Motion Panne, Display Pannel, Utilities Pannel 이라고 불리웁니다. 마우스를 올려보면 이름이 나옵니다.

 

 

가지(Branch)

 

Branch 란 용어는 우리말로 하자면 '나무가지' 정도 되겠죠. 나무를 각 패널(Pannel) 이라고 하자면 위의 그림에서 Box, Cone, Sphere, GeoSphere 등의 하위기능이 가지라고 할 수 있습니다. 물론 맥스 자체에서는 Branch 라는 단어를 사용하지는 않는 것 같습니다만, SDK 에서는 자주 사용하더군요. 일단 알아두는 것이 좋을 것 같습니다.

 

1. 커맨드 패널에 플러그인 추가

 

현 단계까지 플러그인을 제작했고 맥스에 플러그인 디렉토리를 설정했다면 아래 스샷에 있는 여러 개의 윈도우 모양의 버튼을 누릅니다. 마우스를 올렸을 때 그 버튼에 대한 설명은 "Configure Button Sets" 라고 되어 있군요. "버튼 집합 설정하기" 정도가 되겠습니다. 즉 커맨트 패널에 나오는 플러그인 버튼 집합을 설정하는 메뉴라는 것입니다.

 

 
이 버튼을 누르면 다음과 같은 다이얼로그가 뜹니다.


 
1번은 커맨드 패널에 출력할 버튼의 개수를 나타냅니다. 현재 기본값은 9개로 설정되어 있을 것입니다. 우리는 우리의 플러그인 버튼을 추가할 것이기 때문에 10으로 값을 변경합니다. 그리고 왼쪽의 2번은 우리가 추가한 CustomPlugins 카테고리의 CMyPolygonCounter 플러그인의 이름이 있습니다.
 
오른쪽 버튼의 스크롤바를 내려 보면 다음과 같이 빈 버튼 자리가 있는 것을 볼 수 있습니다.
 
 
빈 버튼을 선택하면 노란색 테두리가 생기는게 보이시죠? 노란색 테두리가 생기면 왼쪽의 CMyPolygonCounter를 더블클릭합니다. 그러면 다음 그림처럼 버튼이 추가됩니다.
 
 
그런데 여기에서 주의할 점은 노란테두리가 reactor 나 MAXScript 등 다른 버튼에 있을 때 왼쪽을 더블클릭하면 그 버튼이 대체되어 버린다는 것입니다. 빈 공간을 선택하고 더블클릭해 주십시오.
 
이제 OK 를 누르면 다음과 같이 커맨드 패널이 변경되어 있는 것을 확인하실 수 있습니다.
 
 
이제 우리는 CMyPolygonCounter 버튼을 사용해서 우리의 플러그인을 실행할 수 있습니다.
 
2. CMyPolygonCounter::BeginEditParams
 
자 우리가 커맨드 패널의 CMyPolygonCounter 라는 버튼을 눌렀을 때 어떤 일이 발생할까요. 제목으로 벌써 눈치 채셨겠지만 UtilityObj::BeginEditParams 가 호출됩니다. 물론 우리가 재정의한 함수를 호출하게 됩니다. 이것의 선언을 살펴보도록 하죠.
 
virtual void BeginEditParams(Interface* ip, IUtil* iu) = 0
 
이것은 플러그인에 의해서 구현됩니다. SDK 설명으로는 "플러그인이 커맨드 패널의 가지(branch)에서 사용될 때 호출된다. 예를 들어 플러그인은 이 메서드에서 커맨드 패널에 롤업(rollup) 페이지를 추가할 수 있다" 라고 되어 있군요.
 
감을 잡으신 분도 있겠지만 이 메서드에서 다이얼로그를 생성하면 됩니다. 다음과 같이 코드를 작성할 수 있겠죠.
 
void CMyPolygonCounter::BeginEditParams(Interface *ip,IUtil *iu) 
{
    this->iu = iu;
    this->ip = ip;
 
    // 이미 다이얼로그가 존재하면
    if(NULL != m_hDlg)
    {
        // 다이얼로그를 활성화한다
        SetActiveWindow(m_hDlg);
    }
    // 다이얼로그가 존재하지 않으면
    else
    {
        // 다이얼로그를 생성한다
        m_hDlg = CreateDialogParam(hInstance, 
            MAKEINTRESOURCE(IDD_POLYGONCOUNTER),
            ip->GetMAXHWnd();, 
            MyPolygonCounterDlgProc, 
            (LPARAM)this);
 
        ShowWindow(m_hDlg, SW_SHOW);
    }
}
 
여기에서 왜 그냥 다이얼로그를 띄우지 않고 m_hDlg가 있는지를 확인하느냐에 대한 의문이 들 수 있습니다. 그것은 이 다이얼로그가 Modeless Dialog 이기 때문인데요, 폴리곤 카운터가 떠 있는 상태에서도 다른 편집 작업이 가능해야 한다는 이야기입니다. 즉 폴리곤 카운터의 플러그인 버튼을 다시 누른다고 해도 새로운 다이얼로그가 생성되는 것은 아니라는 의미입니다.
 
EndEditParams 가 호출된다고 해도 폴리곤 카운터 다이얼로그는 없어지지 않습니다. 그렇기 때문에 폴리곤 카운터가 떠 있는 상황에서는 버튼을 다시 누른다고 해도 그냥 활성화만 할 뿐이죠.
 
ip->GetMAXHWnd() 는 맥스가 실행되고 있는 윈도우 핸들을 반환합니다.
 
MyPolygonCounterDlgProc 는 다이얼로그 프로시저인데 아마도 CMyPolygonCounterDlgProc 로 생성되어 있을 것입니다. 거기에서 C를 뺐습니다.
 
3. CMyPolygonCounter::EndEditParams
 
이름에서 느낄 수 있듯이 폴리곤 카운터 플러그인 버튼이 해제될 때 호출됩니다. 이것이 해제되는 경우는 두 가지입니다. 첫번째는 다른 플러그인 버튼을 클릭했을 때이며, 두번째는 다른 커맨드 패널을 선택했을 경우입니다. 즉 버튼이 눌려있다는 표시인 노란색이 없어지는 경우를 말하는 것입니다.
 
BeginEditParams 에서도 언급했지만 폴리곤 카운터가 없어지는 것은 다이얼로그에서 IDCANCEL 이나 IDOK 통지가 발생했을 경우이지, EndEditParams 가 호출되는 경우가 아닙니다. 그래서 우리는 여기에서 아무런 작업도 수행하지 않습니다.
 
4. MyPolygonCounterDlgProc
 
//--- 다이얼로그 프로시저 -------------------------------------------------------
static BOOL CALLBACK MyPolygonCounterDlgProc(
                        HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg) 
    {
     case WM_INITDIALOG:
        // 폴리곤 카운터 초기화 작업
        theCMyPolygonCounter.Init(hDlg);
        break;
 
    case WM_DESTROY :
        break;
 
    case WM_COMMAND:
  
        switch(LOWORD(wParam))
        {
            case IDCANCEL :
            case IDOK :
                // 폴리곤 카운터 종료 작업
                theCMyPolygonCounter.Destroy(hDlg);
            break;
        }
        break;
 
    default:
        return FALSE;

    }
 
    return TRUE;
}
 
위에서 theCMyPolygonCounter 는 폴리곤 카운터의 전역 인스턴스입니다. Init 와 Destroy 는 프로젝트를 생성할 때 자동으로 정의된 메서드입니다.
 
그런데 WM_DESTROY 가 아니라 Destroy 에서 종료처리를 하는 것에 대해서 의문을 가지실 것이라 생각합니다. 그 이유는 EndDialog 가 다이얼로그를 바로 해제하는 것이 아니기 때문입니다. 즉 WM_DESTORY 에서 종료 처리 작업을 하면 맥스를 종료할 때까지 종료 처리가 되지 않을 수 있습니다. 그러므로 theCMyPolygonCounter.Destroy(hDlg) 를 호출하여 종료 처리를 합니다.
 
5. CMyPolygonCounter::Init(HWND hDlg)
 
이 메서드는 초기화 작업을 수행합니다. 초기화작업이래야 별거 없고, 인터페이스에 폴리곤 카운터 다이얼로그를 등록하는 작업과 폴리곤 카운터 다이얼로그를 화면 중심에 배치하는 작업입니다.
 

void CMyPolygonCounter::Init(HWND hDlg)
{
    

    // 다이얼로그 등록
    ip->RegisterDlgWnd(hDlg);

 

    // 맥스 윈도우 너비 구함
    RECT Rect;
    GetWindowRect(ip->GetMAXHWnd(), &Rect);
    LONG lWidth = Rect.right - Rect.left;
    LONG lHeight = Rect.bottom - Rect.top;

 

    // 다이얼로그 너비 구함
    RECT DlgRect;
    GetWindowRect(hDlg, &DlgRect);
    LONG lDlgWidth = DlgRect.right - DlgRect.left;
    LONG lDlgHeight = DlgRect.bottom - DlgRect.top;

 

    // 다이얼로그의 위치 재설정
    MoveWindow(hDlg, (lWidth - lDlgWidth) / 2, 
                         (lHeight - lDlgHeight) / 2, lDlgWidth, lDlgHeight, TRUE);

}

 

여기에서 주의해야 할 점은 m_hDlg 를 사용하지 않고 인자로 넘어온 hDlg 를 사용한다는 것입니다. 왜냐하면 WM_INITDIALOG 는 CreateDialogParams 가 값을 반환하기 전에, 즉 m_hDlg 가 할당되기 전에 호출되는 것이기 때문입니다.

 
 
6. CMyPolygonCounter::Destroy(HWND hDlg)
 
여기에서는 인터페이스에 등록했던 폴리곤 카운터 다이얼로그를 등록 해제하는 작업을 수행합니다. 또한 커맨드 패널에서 선택되어 있던 폴리곤 카운터 버튼을 선택 해제합니다.
 
void CMyPolygonCounter::Destroy(HWND hDlg)
{
 
     // 다이얼로그 닫는다
    EndDialog(hDlg, FALSE); 
 
    // 다이얼로그 등록 해제
    ip->UnRegisterDlgWnd(hDlg);
 
    // 선택 상태를 해제한다
    iu->CloseUtility();
 
    // 멤버 초기화
    m_hDlg = NULL;
    iu = NULL;
    ip = NULL;
}
 
여기에서 iu->CloseUtility() 가 버튼의 선택을 해제하게 만드는 메서드입니다. 이 메서드를 호출하게 되면 EndEditParams 를 호출하게 됩니다. 만약 EndEditParams 내부에서 iu->CloseUtility() 를 호출하게 되면 서로를 계속해서 호출하게 된다는 점에 주의하시기 바랍니다.
 
그리고 m_hDlg = NULL 을 할당하는 것은 매우 중요합니다. 그렇게 하지 않으면 다시 BeginEditParams 를 했을 때 다이얼로그를 생성하지 않게 됩니다.
 
7. 정리
 
플러그인 버튼을 누를 때 BeginEditParams 가 호출되며, 여기에서 다이얼로그 생성 및 초기화 작업을 수행합니다. 그리고 다이얼로그에서 IDOK 나 IDCANCEL 통지가 발생했을 때 플러그인을 해제하고, 플러그인 버튼 선택을 해제합니다.
 
말로는 간단한데 직접 순서를 느낄 수 있는 가장 쉬운 방법은 MessageBox 를 사용해서 호출 순서를 출력해 보는 것입니다.
 
MyPolygonCounter.cpp 소스 코드를 첨부했습니다.
 
8. 주의 사항
 
MyPolygonCounter.dlu 파일을 쓰기 모드로 열 수 없다는 링크 에러가 나면 맥스 프로그램이 실행중인지를 확인해 보시기 바랍니다.
브레이크 포인트 히트, 빌드성공, 실패, 캔슬에 대한 효과음 출력을 지정해줄 수 있는 것을 아시나요?

현재 VS2008 과 2005에서 가능한 것을 확인하였습니다. .net 에서는 잘 모르겠네요.

 단, 2005에서는 브레이크 포인트 히트시 밖에 설정하지 못합니다.


윈도우 비스타 기준으로 [바탕화면 오른쪽 클릭 ->  개인 설정 -> 소리 ] 혹은 제어판을 통해서 들어가셔도 됩니다.

XP 는 제어판을 통해서 들어가셔야 됩니다.


윈도우 효과음 설정 목록이 나오면 아래쪽에 Visual Studio 항목을 찾습니다.


 

비스타에서 효과음 설정 하는 부분입니다.

위 이미지 처럼 각각 상황에 대해서 효과음을 설정해줄 수 있지요.

VS2008의 경우 Microsoft Visual Studio 항목으로 나오고 VS2005의 경우 decenv 항목으로 나옵니다.


이렇게 해서 좋은 점이 뭐냐고요? 이런게 무슨 팁이냐구요?


첫째, 빌드 실패, 성공에 대한 여부를 효과음으로 더욱 빠르게 캐취해낼 수 있습니다.

둘째, 조금 시간이 걸리는 소스일때 백그라운드에서 돌려놓고 사운드로 캐취할 수 있습니다.

셋째, 비주얼 스튜디오 빌드나 디버그에서 상큼한 효과음을 들으면서 작업 능률이 오를 수 있겠습니다. (ㅡㅡ;;;;)


전혀 설득력 없는 이유네요. ㅡㅡ;


그래도 상큼한 사운드를 설정해놓으니 뭔가 색다른 느낌이 드는게 재밌습니다.

첫째와 둘째의 경우 전혀 뻥은 아니에요 ^^

시작 하며 ...

사실 회사에서 문서화 작업을 하며 만든 걸 가져다 올린 것이긴 하지만...

아무튼 Doxygen에 처음 접하는 사람들에게 유용하였으면 합니다. 붙여넣기 신공을 펼치긴 했지만

아무튼... 전 이만...

 

* Doxygen 이란?

 - Doxygen은 소스상에서 간단한 주석으로 문서를 만들 수 있도록 도와주는 유틸리티로써 다양한 언  어에 대해서 지원이 가능하며 팀 작업상에서 유용한 정보를 제공 할 수 있다.

 

* Doxygen 프로그램의 이용법



 












 

ㅡ.,ㅡ;;; 많기도 하다.

 

  * 문서화를 위한 명령어

 명령어  설명
 /*! .... 생략 .... */ 각 명렁어를 묶는 주석 
 \class 클래스 이름
 \brief 설명
 \date 날짜
 \author 작성자
 \f 함수명
 \param 파라메터
 \return 리턴값
 \defgroup 그룹 생성
 \addtogroup 생성된 그룹에 추가


 

  * 명령어의 사용 예

   - 클래스와 함수에 대한 주석 예제

 

///////////////////////////////////////////////////////////////

/*!                                                  <- 여기서부터

\class     QtClass                                   클래스의 이름을 기입

\breif     테스트를 위한 클래스                      클래스에 대한 설명부

\date      2008-06-21                                작성된 날짜

*/                                                   <- 여기까지 하나의 클래스의 주석이 된다.

///////////////////////////////////////////////////////////////

class QtClass

{

private :

 

             int                                     m_iNumber;

             float                                   m_fNumber;

             char                                    m_strName[128];

 

 

public :

 

             ///////////////////////////////////////////////////////////////

             /*!

             \f        Init()

             \brief    초기화함수

             \date     2008-06-21

             \author   문성민

             \param    void

             \return   void

             ///////////////////////////////////////////////////////////////

             */

             void                                    Init();

 

 

};

 



- 위 예제 소스를 문서화 하였을 때에 위 사진과 같이 나오게 된다. -

 

  * 그룹화에 대한 주석 예제

 

///////////////////////////////////////////////////////////////

/*!

\addtogroup    QtClassGroup                          QtClassGroup에 추가 한다

\{                                                   그룹에 추가 범위의 시작

\date          2008-06-21

\breif         QtClass_2를 그룹에 추가함

*/

///////////////////////////////////////////////////////////////

 

///////////////////////////////////////////////////////////////

/*!Details about

\class    QtClass_2

\breif    테스트용

\date     2008-06-21

*/

///////////////////////////////////////////////////////////////

 

class QtClass_2 : public QtClassBase

{

private :

 

             int          m_iNumber;

             QtClass_1*   m_pQtClass_1;

 

public :

 

             /*! \f       \brief    속성변경 \date     08-06-21    \author   문성민 */

             int          SetProperty( int I );     

 

             QtClass_2();               ///< 기본생성자

             ~QtClass_2();              ///< 기본소멸자

};

 

/** \} */                                            그룹 추가 범위의 끝

 

*** 여기서 중요한 것은   \{   ......  \}  중괄호 중간에 클래스나 함수가 있어야 된다.

 




- 그룹화를 하였을 때에 되는 문서화 예제

 

  * 클래스 계층도에 대한 예제

   - 클래스 계층도는 Export 설정에서 Diagram 옵션을 끄게 되면 나오지 않는다.

  





 

  * 메인 페이지를 꾸밀 시에 예제

/** \mainpage Doxygen Test                           메인 페이지의 제목을 설절

    \section developer 개발자                        개발자에 대한 이름

        문성민

       

    \section info 개발목적                           개발 목적

        - Doygen 문서테스트용소스                   

 

    \section advenced 추가정보                       추가적인 정보를 여기서 넣으면 된다.

        글머리는'-' 태그를사용하면되며

            탭으로들여쓸경우하위항목이된다.

        -# 번호매기기는'-#' 방식으로할수있다.

            -# 위와같이탭으로들여쓸경우하위항목이된다.

            -# 두번째하위항목

        이런식으로그림을넣을수도있다.

 

                           \image html gom.jpg        // 이미지를 넣을 수 있다.

*/

 

 

* 매크로 작성법

 매크로에 대한 작성은 비주얼 베이직을 이용하여 작성을 할 수 있다.



Tools -> Macro -> Macro Explorer 를 선택을 하면 우측에 Explorer창이 뜨게 된다.

여기서 New Macro Project를 선택을 하여 새로운 프로젝트를 생성을 하여 아래 코드를 입력을 한다.

 

Imports System

Imports EnvDTE

Imports EnvDTE80

Imports EnvDTE90

Imports System.Diagnostics

 

Public Module AddGroup

    Sub InsertModuleComments()

        Dim module_name As String

        module_name = InputBox("추가클래스이름:")                 // 다이얼로그 박스를 띄워서 이름을 입력을 한다.

        If (module_name <> ""Then

            Dim textSelection As EnvDTE.TextSelection

            textSelection = DTE.ActiveWindow.Selection

           textSelection.Insert("///////////////////////////////////////////////////////////////")       //텍스트를 추가 한다.

           textSelection.NewLine()                                                                       //줄을 바꾼다.

            textSelection.Insert("/*!")

            textSelection.NewLine()

            textSelection.Insert("\addtogroup    " + module_name)                                         // + 연산으로 문자열을 추가 할 수 있다.

            textSelection.NewLine()

            textSelection.Insert("\{")

            textSelection.NewLine()

            textSelection.Insert("\date        " + Format(System.DateTime.Now,"yyyy/MM/dd"))                          // 자동으로 현재 날짜를 입력해준다.

            textSelection.NewLine()

            textSelection.Insert("\breif       ")

            textSelection.NewLine()

            textSelection.Insert("*/")

            textSelection.NewLine()

           textSelection.Insert("///////////////////////////////////////////////////////////////")

            textSelection.NewLine()

            textSelection.Insert("/** \} */")

 

        End If

    End Sub

 

End Module

 

위 예제는 그룹을 추가 할 때에 대한 매크로이다.

이를 컴파일을 하고 Tools -> Customize -> Keyboard 를 선택을 하여 단축키로 등록을 한다.

회사에서 클라이언트 팀에서 처음으로 세미나라는 것을 했다.
그때 발표를 할 때 내머리 속의 지우개가 있는 듯 했다.
그때 아직 3개월도 채 되지 않은 나이기에.... 음. 다시 생각 해보니 지금은 3개월 하고 일주일이 넘었군...
아무튼 그때 발표할 때 썼던 문서를 다시 정리 해 보겠다. 귀찮아서... 대충만... ㅡ.,ㅡ;;
완전 허접하지만 이뿌게 봐주시길...

* 스크립트란?
 초기 스크립트언어는 일련의 반복적인 명령들을 일종의 명령 처리기에 집어넣는 수단이었다.
이가 발전 함에 따라서 용도가 변하여 빠른 개발을 위해 쓰이며 비 프로그래머가 읽고 쓰기 쉬운 텍스트 기반 구문을 채용하는 도구로 변모하였다. 
일정한 지식을 갖춘 사용자라면 프로그래머의 개입 없이도 스스로 스크립트를 작성하고 사용할 수 있다.

* 루아란?
 루아는 “접착제(glue)” 언어라는 점에서 위의 스크립트언어와 차별된다. 
기존의 스크립트 언어들은 반복적인 작업을 처리하는 용도지만 루아는 사용자가 다른 언어의 기능과 공정을 함께 “접착해서” 통합하기 위한 도구로 만들어진 것이다. 
이런 방식은 단순히 명령들을 수행하는 것 이상의 일을 할 수는 강력한 도구이다.

* 루아의 장단점
- 장점
루아는 애초부터 좀 더 큰 응용 프로그램에 내장 시킬 것을 목적으로 고안된 언어이기에
확장성이 크다. 루아와 C언어의 통신이 쉬우며 기술적 설계안에서 구현하기 비교적 쉽다.
루아는 작고 빠르며 이식성이 뛰어나다. 이 말인즉 실행시점 메모리 사용량 측면에서 부담이 적고, C보다는 느리지만 파이썬과 같은 언어보다 빠르다. 
그리고 새로운 하드웨어로 옮긴다해도 큰 수정없이 가능하다.

- 단점 
루아는 파이썬에 비해 지원 라이브러리가 부족하다.
루아에 대한 소개자료가 아직은 부족한 편이다.
단독 실행 인터프리터로서 사용하기에는 빈약하다.

* 루아가 게임 개발에 적합한 이유
- C++과 연동이 잘되며 C++을 이용해서 확장할 수 있다.
- 확장성이 뛰어나 기술적 설계안에서 구현하기 쉽다.
- 작고 빠르며, 이식성이 뛰어나다.
- C를 접해본 사람이라면 배우기 쉽다.
- 그리고 무료이다.

* 루아의 사용처
- 게임내의 UI를 제작
 UI는 루아를 이용하여 조작할 수 있고 유저가 루아를 통해서 UI로 커스텀마이징 가능하다.
- 게임의 자료의 정의, 저장, 관리
 데이터 주도적 설계를 할 수있다. 모든 객체의 매개변수와 특성을 정의하여 하드 코딩을 통한 구현보다 외부 데이터로 관리하는 편이 데이터 수정이나 추가면에서 많은 이득을 볼 수있다.
- 실시간 게임 사건들의 관리
 일반적으로 게임 내부에서 상호작용간에는 이벤트가 발생하는데 , 이러한 것을 관리 할 수있다.
- 게임의 인공지능 시스템을 작성
 인공지능을 루아로 제어가 가능하다. 이를 이용하여 스크립트 작업자가 프로그래머 없이 작성이 가능하고, 이후에 유저가 직접 AI를 구성할 수 있다.


* 루아 스택이란?
- 루아는 C에서 사용하는 메모리 공간과는 별도의 메모리 공간을 사용을 하는데
이를 스택이라고 부른다. 스택은 루아의 명령 및 변수등의 데이터를 저장하고 있다. 
이 스택은 아래에서 부터 쌓여 나가며 이에 접근하기 위해서 인덱스를 사용하고 있는데
인덱스는 문자열을 이용하여 인덱스로 변환을 해서 사용을 한다. ( 이 부분은 뒤에 자세한 설명 )







에구... 연신 붙여넣기 하면서 귀찮은 부분은 않했는데...
나중에 다시 작업 하겠습니다.

흐미... 몇일 지나서 하는거야... ㅡ.,ㅡ;;;

현재 되는 기능을 나열 해보겠다.
나열하기 전에 용어에 대해서 정의를 하고 넘어 간다.
C는 우리가 작업을 하는 C, C++을 통합적으로 말하는 것이고 당연히 닷넷등의 컴파일러상의 언어를 말한다. 
루아는 루아문법을 말한다. 
값( Value )은 Value 즉 포인터가 아닌 실제 값을 말한다.

1. C 와 루아간의 함수 호출
  C함수를 루아스택에 등록을 하고 루아 함수를 C에서 호출 가능하고
2. C 와 루아간의 Value를 주고 받을 수 있다.
3. C의 클래스를 루아 스택에 등록을 한다.
4. 루아 스택에 등록이 된 C 클래스의 인스턴스 포인터를 넘겨서 
   루아 스택에서 바로 조작이 가능하다. 

개인적으로 4번이 가장 유용하고 많이 쓰이는 것 같다. 
언리얼 엔진은 메인 뷰어를 두고 밑에 에디트 창을 통해서 메인 뷰어( 게임 화면 )의 객체를 조잘 할 수 있다고 한다.
현재 작업은 그런식으로 가능하게 되는데 상당히 유용한 듯하다.
이번주에 작업을 해서 화면의 싸이즈를 변경한다 든지 백그라운드 색상을 바꿀수 있는데 
어찌나 좋던지...^^ㅋㅋㅋㅋ

앞으로는 AI와 UI의 이벤트 처리를 해볼 것이다. 
다른 사람들은 어떻게 사용하는지 모르겠지만 어째든 유용하게 사용하고 있는듯 하다.

루아 스크립트 문장을 콘솔에서 간단히 돌려보는 방법은

 

첨부 파일에 포함된 파일

 

/*

bin2c5.exe

 

lua5.exe

 

luac.exe

*/

 

위의 세 가지 이다. 위의 세 파일을 C:\WINDOWS  또는  C:\WINDOWS\system32 폴더안에 넣고 Editplus, Acroedit 와 같은 에디팅 프로그램에서 lua5.exe 파일을 사용자도구로 설정을 해 놓으면 간단히 루아 스크립트 문장을 실행해 볼 수 있다.

 

                                        < Editplus 에서 사용자 도구 설정 화면 >

메뉴에서 [도구] 탭을 보면 실행 바로 가기 키를 확인할 수 있다.

 

print("출력 테스트")

 

다음과 같이 문장을 입력하여 확장자를 lua 파일로 저장하고 실행해 보면 콘솔 화면에서 문자열이 출력 되는것을 볼 수 있다.

 

 

 

 

(※ 레퍼런스 매뉴얼을 보고 마음대로 해석하여 공부한 것이니 잘못 된 부분이 있을지도 모릅니다. 잘못된 부분 있으면 가르쳐주시면 감사하겠습니다. ^^; )

 

 

루아의 문자열은 문자와 숫자, 언더바로 구성할 수 있으며 처음을 숫자로 시작할 수는 없다.

 

루아의 예약어는 다음과 같은 것들이 있다.

 

and break  do  else  elseif   
end  false  for  function  if   
in  local  nil  not  or   
repeat  return  then  true  until  while 

 

 

대 소문자를 구분하므로 And 와 AND 는 다르게 구분된다.

 

_ (underbar) 로 시작하여 대 문자가 적힌것은 예약된 내부의 변수이다. (예 : _VERSION)

 

 

그 외의 토큰들에는

 

+    -    *   /    ^    =      ~=     <=      >=        <         >         ==       (        )         {       }

 

[   ]        ;    :      ,     .     ..     ...

 

문자열은  두 개의 ' (single quotation mark)  " (double quotation mark) 안에 들어가야 하며 C언어 같은 이스케이프 시퀀스가 사용된다.

 

 

\a    ㅡ    경보음 (bell)

\b    ㅡ    백스페이스 (backspace)

\f    ㅡ     폼 피드 (formfeed)

\n    ㅡ    개행     (newline)

\r    ㅡ     리턴     (Carriage return)

\t    ㅡ     수평 탭 (horizontal tab)

\v    ㅡ    수직 탭 (vertical tab)

\\    ㅡ   역 슬래쉬 (backslash)

\"    ㅡ     큰 따옴표 (double quotation mark)

\'    ㅡ     작은 따옴표 (single quotation mark)

\[   ㅡ      왼쪽 브라켓 (left square braket)

\]    ㅡ     오른쪽 브라켓 (right square breket)

 

 

문자열은  '   "   외에도  [[   ]]   안에 들어갈 수도 있다.

 

차이점은   '  나  "  는 여러 한 라인 내의 문자열만 가능하지만 [[   ]] 은 여러줄에 걸쳐 선언된 문자열도 가능하다는 것이다.

 

print("alo\n123\"")
print("\n")

print('\97lo\10\04923"')
print("\n")

str1 = [[alo
123"]]
print(str1)
print("\n")

str2 = [[
alo
123"]]
print(str2)

 

 

다음을 실행 해 보면 같은 문자열이 출력된다.

 

두 번째 출력에서 \10은 \n 으로 개행이 되고 \0 뒤의 49는 ASCII 코드 값인 1이 되어 출력이 된다.

 

 

숫자 상수는 10진 또는 16진수로 쓰여진다.

 

예) 3     3.0       3.14        3.1416e-2          0.31416E1

 

 

 

주석은  한 줄 주석을 달 때는 --   하이픈 두개 를 사용하고

 

여러 줄 주석을 달 때는   --[[   와   --]]  를 사용한다.

 

예)

 

-- 한줄 주석

 

--[[  여러

주석

--]]

MFC의 Picture Control을 사용을 하다보면 

저기에 내가 원하는 픽셀을 넣고 싶을 경우가 있다.

예를 들어 툴을 만들때에 동적인 Teuxtre를 미리보기 형식으로 다이얼로그에 넣을 때 말이다

그럴경우에 대한 경우에 한가지 방법은 (사실 이 방법밖에 알아내지 못했다.)

Picture Control을 만들고 Picture Control의 윈도우 핸들을 가지고 비트맵을 생성을 하고 

그에 대한 픽셀 데이터를 가지고 온다. 그리고 Picture Control에 생성한 비트맵을 지정해준다.

그리고 나서 내가 원하는 텍스처나, 랜더 타겟의 비트맵을 얻어와서 앞서 생성한 비트맵의 픽셀 

데이터에 넣어주면 된다. NDL을 사용할 경우는 랜더타겟의 픽셀을 가지고 오는 과정에서 LockReck을

했을 경우에 실패를 하게 되는데 정확한건 아니지만 POOL_DEFAULT로 되어 있을 경우에 실패를 하지 

않나 싶다. 엔진에서 픽셀을 함부로 접근하지 못하게 하기 위해서 그런듯 하다.

그런 경우에 굳이 나처럼 랜더타겟을 보여주고 싶으면, 임의의 섭페이스를 만들고

랜더타겟의 섭페이스를 임의의 섭페이스로 복사를 한다. 이 임의의 섭페이스는 접근 가능한

섭페이스기에 LockReck을 이용하여 접근을 하여 원하는 데이터를 뽑아 올수 있지만

퍼포먼스를 보장을 못한다. 그렇기에 특정 이벤트가 들어올 경우에만 갱신을 하고 영역 자체를

작게 잡으면 실시간은 무리더라도 특정 이벤트시에 갱신만 해준다면 나름(?) 사용이 가능하다.

// 섭페이스 복사
D3DXLoadSurfaceFromSurface(
pDestSurface,   // 대상 섭페이스
NULL, // 색상파렛트인데.. 모름
pDestRect, // 대상의 복사 될 영역
pSrcSurface, // 복사할 섭페이스
NULL, // 색상파렛트인데.. 모름
pSrcRect, // 복사할 섭페이스의 역역
Filter, // 필터는 DX도움말 참조
ColorKey // 컬러키라는데...모름
);

여러개의 윈도우 위치(multiple-window-position)를 위한 메모리를 할당하고 구조체에 Handle을 리턴한다.
여러개의 윈도우를 재배치 할때는 화면의 껌뻑임을 줄이기 위해 DeferWindowPos 함수를 사용한다.

 

사용방법은 메모리를 할당 한 후 사용하고 해제한다.

 

1.BeginDeferWindowPos(메모리 할당)

 

HDWP BeginDeferWindowPos(
  int nNumWindows   // number of windows
);
여러개의 윈도우 위치(multiple-window-position)를 위한 메모리를 할당하고 구조체에 Handle을 리턴한다.

 

 

2.DeferWindowPos

 

HDWP DeferWindowPos(
  HDWP hWinPosInfo,      // handle to internal structure
  HWND hWnd,             // handle to window to position
  HWND hWndInsertAfter,  // placement-order handle
  int x,                 // horizontal position
  int y,                 // vertical position
  int cx,                // width
  int cy,                // height
  UINT uFlags            // window-positioning flags
);


열거된 여러개의 윈도우 위치(multiple-window-position)를 업데이트한다. 
업데이트된 구조체의 핸들을 리턴한다.

hWinPosInfo : 한개이상의 윈도우에 대한 크기, 위치정보를 포함한 multiple-window-position 구조체 핸들
              이 구조체는 비공개 구조체로 BeginDeferWindowPos에 의해 리턴되거나 최근에 콜한 DeferWindowPos에 의해 리턴된다.
hWnd : handle to window to position
hWndInsertAfter : placement-order handle(SetWindowPos 참조)
x,y : 위치
cx, cy : 크기
uFlag : window-positioning flags(SetWindowPos 참조)

 

리턴값 : 업데이트된 구조체

 

3.EndDeferWindowPos(메모리 해제 및 변경)

 

BOOL EndDeferWindowPos(
  HDWP hWinPosInfo   // handle to internal structure
);

한번의 리플레쉬로 한개이상의 윈도우의 위치,사이즈를 동시에 변경한다.

< 윈도우의 변경 >

- BOOL MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight,  BOOL bRepaint);
윈도우의 위치, 크기를 동시에 변경하는 가장 기본 적인 함수


- BOOL SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlag);
윈도우의 위치, 크기, Z순서를 변경(바로 앞에 있을 윈도우의 핸들값을 주거나 HWND_TOP, HWND_BOTTOM..등의 값도 줄 수 있다 )할 수 있으며 크기 변경 및 이동에 몇가지 옵션(uFlag)을 줄 수 있다.
!!!!!개별 윈도우의 위치나 크기, Z순서를 바꿀때~


- HDWP BeginDeferWindowPos(int nNumWindows);
HDWP DeferWindowPos(HDWP hWinPosInfo, HWND hWnd, HWND hWndInsertAfter, int x, int y, int cx, int cy, UINT uFlags);
BOOL EndDeferWindowPos(HDWP hWinPosInfo);
!!!!!여러개의 윈도우를 일괄 조정 한다.( 따라서 화면 깜박임이 덜하고, 재배치 속도가 빠르다.)



- BOOL SetWindowPlacement(HWND hWnd, CONST WINDOWPLACEMENT *lpwndpl);
BOOL GetWIndowPlacement(HWND hWnd, WINDOWPLACEMENT *lpwndpl);
윈도우의 위치, 크기, 최대, 최소 상태를 한꺼번에 조사 및 변경 할 수 있다.
(최대화 된 메모장을 다시 원래대로 복구해 보면, 최대화 되기 전의 노멀 좌표(자기 자신의 좌표)로 정확하게 찾아간다. 이것은 시스템이 윈도우의 노멀 좌표를 기억하고 있기 때문이다.)

+ Recent posts