GSI

Dialog Form (MFC) 를 개발하다 보면 CView, CScroll, CHtmlView 등과 같은
뷰의 클래스를 추가 하고 싶을때가 있다.

하지만 동적으로 생성하는 방법을 사용해서
CMyView* pMyView = new CMyView();
pMyView.Create(...);
pMyView.ShowWindow(SW_SHOW);

이런 방법을 사용하게 되면 생성후에 화면에 제대로 나오는걸 확인할 수 있다.
하지만 종료할때 보면 디버그 에러가 발생하게 된다.

자세한 이유는 모르겠다. 하지만 분명한건 아래와 같은 RUNTIME_CLASS() 를 사용해서 생성해야 하는걸 확인하였다.
아래와 같이 코드를 작성해서 추가를 해보면 이상없이 동작하는 것을 확인할 수 있다.

///
BOOL CDlgTestViewDlg::OnInitDialog()
{
...
 CCreateContext pContext;
 /**
 * Note:CDialig derived pointer is converted to
 * CWnd pointer (a common base class for CDialog and CFrameWnd).
 * Thus casting it back to CFrameWnd is also easy.
 */
 CWnd* pFrameWnd = this;
 
 pContext.m_pCurrentDoc = new CDocument;
 pContext.m_pNewViewClass = RUNTIME_CLASS(CTestView);
 CTestView *pView =
  (CTestView *) ((CFrameWnd*)pFrameWnd)->CreateView(&pContext);
 ASSERT(pView);
 pView->ShowWindow(SW_NORMAL);

 /**
 * After a view is created, resize that to
 * have the same size as the dialog.
 */
 CRect rectWindow;
 rectWindow = CRect(10, 10, 100, 100);
 /**
 * Leave a little space for border and title...
 */
 pView->MoveWindow(rectWindow);

...

 return TRUE;
}
Posted by gsi
:

다이얼로그 투명하게..

C++ 2007. 10. 4. 11:29 |

BOOL SetLayeredWindowAttributes(
  HWND
hwnd,           // handle to the layered window
  COLORREF crKey,      // specifies the color key
  BYTE bAlpha,         // value for the blend function
  DWORD dwFlags        // action
);

typedef SLWA

선언:

typedef BOOL (WINAPI* SLWA)(HWND hWnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags);

#ifndef WS_EX_LAYERED
#define WS_EX_LAYERED       0x00080000
#define LWA_ALPHA           0x00000002
#endif

코딩:

void CDlgTestDlg::SetTransparency(HWND hwnd, int percent)
{
    SLWA pSetLayeredWindowAttributes = NULL;  // 함수포인터 선언, 초기화.
    HINSTANCE hmodUSER32 = LoadLibrary("USER32.DLL"); // 인스턴스 얻음.
    pSetLayeredWindowAttributes=(SLWA)GetProcAddress(hmodUSER32,"SetLayeredWindowAttributes");
    //함수포인터 얻음.
//  HWND hwnd = this->m_hWnd; //다이얼로그의 핸들 얻음.
    SetWindowLong(hwnd, GWL_EXSTYLE,GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
    pSetLayeredWindowAttributes(hwnd, 0, (255 * percent) / 100, LWA_ALPHA);
}

Posted by gsi
:

union 사용법

C++ 2007. 9. 30. 01:53 |

가끔 공용체가 편할때가 있다 ^^

 union {
  struct {
     float m11; float m12; float m13; float m14;
     float m21; float m22; float m23; float m24;
     float m31; float m32; float m33; float m34;
     float m41; float m42; float m43; float m44;
  };
  struct {
   float m4x4[4][4];
  };
  float m16[16];
 };
Posted by gsi
:

[C++] Cast에 대해서... (펌)

C++ 2007. 9. 20. 17:14 |

관련 주소 : http://blog.naver.com/process3?Redirect=Log&logNo=20017834722
본 글은 cast 쪽을 보면서 자료로 참고 하기 위해서 퍼 왔습니다.

캐스트 연산은 주어진 식이 가지고 있는 형을 다른 형으로 강제로 바꾸는것입니다.

C++에는 (C 시절부터 존재하는 C 스타일 캐스트를 제외하고) 다음 네 가지 종류의 캐스트 연산이 있습니다.

* dynamic_cast
* static_cast
* reinterpret_cast
* const_cast

---------------
1. dynamic_cast
---------------

dynamic_cast(e)는 부모 클래스와 자식 클래스의 관계에 있는 포인터 형 사이의 변환 또는 레퍼런스 형 사이의 변환을 수행하는데,

- 같은 형 사이의 변환
- 널 포인터의 변환
- 자식 클래스로부터 부모 클래스로의 변환
과 같은 '뻔한' 경우가 아니라면 e는 다형적 형(polymorphic type; 가상 함수가 포함된 클래스 형)의 좌변값이나 포인터여야 하며, 컴파일시에 변환이 이루어지는 다른 종류의 캐스트 연산과는 달리 실행시에 동적 형(dynamic type)에 근거한 변환이 시도되고, 변환의 성공 여부를 검사하는 의미도 함께 가지고 있습니다.

포인터의 경우 변환이 실패하면 결과값은 널 포인터가 되는데, 이를 if 등의 조건 검사에 활용할 수 있습니다.

struct animal { virtual void ~animal(); };
struct dog : animal { void bark(); };
struct cat : animal { void mew(); };

void test(animal* a)
{
if (dog* d = dynamic_cast(a)) d->bark(); else
if (cat* c = dynamic_cast(a)) c->mew();
}

레퍼런스의 경우 변환이 실패하면 헤더에 정의되어 있는 std::bad_cast 예외가 발생합니다. 즉 이는 주어진 변환이 성공할 것을 알고 있을 때 주로 사용합니다.

void test(animal& a)
{
dog& d = dynamic_cast(a);
d.bark();
}

dog d; test(d); // 성공
cat c; test(c); // 실패 - std::bad_cast 예외 발생

dynamic_cast와 비슷한 성질을 가지고 있으면서 변환 대신 형 검사만 하는 typeid 연산자도 있는데, 피연산자는 식이나 형이 되고, 연산의 결과값은 헤더에 정의되어 있는 std::type_info 형의 좌변값입니다.

void test_equal(animal& x, animal& y)
{
if (typeid(x) == typeid(y)) { /* 같은 종류 */ }
else { /* 다른 종류 */ }
}

void test_dog(animal& x)
{
if (typeid(x) == typeid(dog)) { /* x is a dog */ }
}

dynamic_cast와 typeid는 C++에서 제공하는 실행시의 형 정보(RTTI; run-time type information)의 일환인데, 이를 남발하면 클래스 체계를 확장하고 관리하기가 어려워지므로 꼭 필요한 경우에만 사용하고 되도록 가상 함수를 통한 다형성을 이용하는 것이 바람직합니다.

--------------
2. static_cast
--------------

static_cast(e)는 가장 일반적인 형태의 캐스트 연산으로, 어떤 임시 변수 t를 T t(e);와 같이 선언하고 초기화하여 그 임시 변수 t의 값을 사용하는 것과 같은 암시적인 변환을 비롯하여, 산술형(char, int, double 등) 및 열거형(enum) 사이의 변환, 부모 클래스와 자식 클래스의 관계가 관련된 변환, void 형으로의 변환 등을 수행할 수 있습니다. 다만 부모 클래스와 자식 클래스 사이의 변환은 주어진 식의 동적 자료형(dynamic type)이 아닌 정적 자료형(static type)에 전적으로 의존합니다.

inline int integer_quotient(double a, double b)
{ return static_cast(a / b); }

animal* a = new dog;
dog* d = static_cast(a); // 올바른 캐스트 연산

animal* a = new cat;
dog* d = static_cast(a); // 잘못된 캐스트 연산

animal* a = new animal;
dog* d = static_cast(a); // 잘못된 캐스트 연산

-------------------
3. reinterpret_cast
-------------------

reinterpret_cast(e)는 서로 다른 형의 포인터 사이의 변환이나, 정수와 포인터 사이의 변환 등 서로 관계가 없는 형 사이의 변환을, 구현체가 정의하는 방법에 따라 수행합니다. 정수와 포인터 사이의 변환의 결과값은 주로 e를 표현하는 비트열을 그대로 정수 및 포인터로 해석한 값이 됩니다.

reinterpret_cast는 그 변환 방법이 대부분 구현체가 정의하도록 맡겨져 있어서 이식성을 떨어뜨리며, 요구된 변환이 올바른 변환인지의 여부를 검사하지 않으므로 신중하게 사용해야 합니다.

unsigned char* const video_base =
reinterpret_cast(0x80000000);

unsigned int ui = 0x01234567;
*reinterpret_cast(&ui) = 0xFF;

-------------
4. const_cast
-------------

const_cast(e)는 const 또는 volatile으로 한정된 형에서 이들을 떼어내는 변환을 수행할 수 있습니다. 이는 C++ 형 체계를 무너뜨릴 수 있으므로 신중하게 사용해야 합니다.

void lie(const int* pci)
{
int* pi = const_cast(pci);
*pi = 0;
}

int i = 1;
lie(&i); // OK

const int ci = 1;
lie(&ci); // Ouch!!


위 네 가지 중에서 dynamic_cast를 제외한 셋은 C에서 (type)expression 의 형태로 사용할 수 있었던 것인데, C++에서도 "C 스타일 캐스트 연산" 이라고 불리며 남아 있기는 합니다만, 새로 작성하는 C++ 코드에서는 C++ 스타일의 캐스트 연산을 사용하는 것이 좋습니다. 이는 어떤 종류의
변환을 프로그래머가 의도하는지 명확하게 나타내 주며, 위험할 수 있는 캐스트 연산이 코드에서 좀 더 두드러져 보이도록 하고 찾기도 쉽게 만들어주기 때문입니다.

위의 내용은 캐스트 연산에 대한 일반적인 설명인데, 좀 더 구체적인 상황에서의 적용 예를 보고 연습을 해 보시려면 GotW #17을 참조해 보시기 바랍니다.



출처 : http://funspace.org/
Posted by gsi
: