레이블이 프로그래밍인 게시물을 표시합니다. 모든 게시물 표시
레이블이 프로그래밍인 게시물을 표시합니다. 모든 게시물 표시

2013년 1월 21일 월요일

32비트 코드를 64비트로 변환(Code Conversion from 32-bit to 64-bit)

윈도우7이 인기를 끌면서 64비트 프로그래밍(64-bit programming)은 거스를 수 없는 대세가 되었다. 아래 정보를 확인해 이전에 짜둔 Visual Studio의 32비트 코드를 64비트로 바꾸어 보자.

[64비트용 솔루션 플랫폼(solution platform) 생성]
1. “구성 관리자 -> 활성 솔루션 플랫폼 -> 새로 만들기”에서 ‘x64’를 추가함

2. “활성 솔루션 구성”에 “Debug x64”, “Release x64”를 추가하고 플랫폼을 모두 ‘x64’로 바꿈: "활성 솔루션 플랫폼"을 'x64'로 바꾸면 모든 솔루션이 x64로 바꾸므로 플랫폼 항목만을 바꾸자.

현재 컴파일러가 64비트 모드에서 동작 중인지 확인하려면 '_WIN64' 정의 여부를 확인하면 된다. 이걸로 확인이 안된다면 "구성 속성 -> C/C++ -> 전처리기 -> 전처리기 정의"에 'WIN64'를 추가하면 해결된다. 한가지 조심할 것은 '_WIN32'이다. 이 정의는 32비트와 64비트 모두에서 사용되기 때문에 '_WIN32'를 이용해 32비트 유무를 판별해서는 안된다. 반드시 '_WIN64'를 써야 한다.

[데이터 변환]
  • int -> INT64, __int64, long long
  • long -> LONG64, __int64, long long
  • unsigned int -> UINT64, usigned __int64, unsigned long long
  • unsigned long -> ULONG64, usigned __int64, unsigned long long
  • INT_PTR, UINT_PTR, LONG_PTR, ULONG_PTR처럼 ..._PTR로 끝나는 변수는 컴파일러가 32비트 모드인지 64비트 모드인지에 따라 선언되는 변수 종류가 자동으로 달라짐
  • int 상수 1 -> 1i64
  • long 상수 1L -> 1LL
  • unsigned int 상수 1 -> 1ui64
  • unsigned long 상수 1UL -> 1ULL 
double에 대해서는 변경할 것이 없다. long double이든지 double이든지 컴파일러는 동일한 코드를 만든다.

[참고문헌]

2012년 10월 16일 화요일

리스트 컨트롤 사용법(How to Use a List Control)

MFC(Microsoft Foundation Class) GUI(Graphical User Interface)에서 많이 사용하는 리스트 컨트롤(List Control)은 다음처럼 쓰면 된다.
CListCtrl m_ctList; // 적당한 곳에 변수 선언
// 리스트 컨트롤 초기화: 양식 설정 m_ctList.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
// 리스트 컨트롤 초기화: 열 추가
m_ctList.InsertColumn(0, _T("번호"), LVCFMT_LEFT, 100);
m_ctList.InsertColumn(1, _T("이름"), LVCFMT_LEFT, 100);
// 리스트 행 추가
m_ctList.InsertItem(0, _T("1")); // 첫째행(0), 첫째열에 삽입
m_ctList.SetItem(0, 1, LVIF_TEXT, _T("가우스"), NULL, NULL, NULL, NULL); // 첫째행(0), 둘째열(1)에 삽입
m_ctList.InsertItem(1, _T("2")); // 둘째행(1), 첫째열에 삽입
m_ctList.SetItem(1, 1, LVIF_TEXT, _T("맥스웰"), NULL, NULL, NULL, NULL); // 둘째행(1), 둘째열(1)에 삽입

[참고문헌]
[2] 쿠식, "CListCtrl 에 관한 정리", 2010.

2012년 4월 26일 목요일

VS2008에서 공백을 점으로 표시

프로그램을 짜다보면 내 코드의 공백을 볼 필요가 있다. 간단히 Ctrl+R과 Ctrl+W를 누르면 된다. 그러면 공백을 점형태로 볼 수 있다. 공백을 나타내는 점을 없애고 싶으면 Ctrl+R과 Ctrl+W를 한 번 더 누른다. 자세한 내용은 [1]을 참조하라.

[참고문헌]

2012년 3월 18일 일요일

VS2008에서 ifstream을 이용한 파일 읽기 문제

특별한 설정을 해주지 않으면 VS2008에서 std::ifstream을 이용해 한글 파일이름과 한글 경로를 가진 파일을 읽을 수 없다. 반드시 아래 코드를 InitInstance()와 같은 함수 내부에 넣어 국가/언어집합(locale)을 한국으로 바꾸어 주어야 한다.
#include <locale>
setlocale(LC_ALL, "Korean");
나모님이 주신 추가의견으로 아래 코드를 사용하면 한국에만 국한되지 않는 프로그램을 작성할 수 있다.
#include <locale>
setlocale(LC_ALL, "");

[참고문헌]
[1] 나모의 노트, "cout", 2011.

2010년 11월 18일 목요일

CListCtrl과 CTreeCtrl에서 한글이 깨진다면?

이전에 잘 출력이 되던 한글이 CListCtrl과 CTreeCtrl에서 갑자기 깨진다면 한글을 쓰는 문자열 집합이 "MS Sans Serif" 등과 같은 영문전용 폰트인지 확인하라. 한글이 깨지면 문자열 집합을 "굴림", "바탕", "고딕"과 같은 한글 폰트로 반드시 바꾸어야 한다.

2010년 10월 12일 화요일

VS2008에서 BSTR 사용방법

플랫폼(platform)에 독립적으로 사용할 수 있는 라이브러리(library)인 COM(Component Object Model)에서 사용하는 문자열 형태는 BSTR(Basic string or binary string)이다. BSTR은 이름에서도 알 수 있듯이 Visual Basic에서 사용하는 문자열 형식이다. 이를 Visual C++에서 쓰려면 아래 형태가 되어야 한다.
BSTR str = ::SysAllocString(L"TestString"); // BSTR에 메모리(memory) 할당
_bstr_t clsStr = str; // BSTR의 캡슐 클래스(encapsulation class) 선언
CString sText = (LPCTSTR)clsStr; // BSTR을 CString으로 변환
캡슐 클래스인 _bstr_t을 사용하지 않으면 BSTR의 메모리 할당(SysAllocString 함수)과 해제(SysFreeString 함수)를 본인이 직접해야 한다. 이게 귀찮으면 그냥 _bstr_t에 할당해서 BSTR을 사용하면 쉽다. BSTR은 thread에 안전한 문자열 형태는 아니므로 multithread 환경인 경우는 아래 code가 더 안전하다. Debug assertion이 뜨는 경우는 아래 형태를 반드시 사용해야 한다.
BSTR str = ::SysAllocString(L"TestString");
_bstr_t clsStr(str, true); // BSTR을 복사해서 캡슐 클래스 생성
::SysFreeString(str); // BSTR의 메모리 해제 CString sText = (LPCTSTR)clsStr;

2010년 10월 11일 월요일

CRichEditCtrl에서 커서(Cursor or Caret)를 문서끝으로 보내기

간단히 아래 code를 사용하자.
CRichEditCtrl REC;
REC.SetSel(REC.GetTextLength(), REC.GetTextLength());
CRichEditCtrl::SetSel(): 선택영역을 결정하며 커서(caret)를 이 위치로 이동시킨다. CRichEditCtrl::GetTextLength(): 현재 문서 총길이를 출력한다. 참고로 원하는 위치에 문장을 출력하려면 아래 함수를 이용한다.
CRichEditCtrl::ReplaceSel(): 현재 선택영역에 문장을 출력한다.
CRichEditCtrl::GetSel(): 현재 선택영역을 얻는다.

VS2008에서 ActiveX COM DLL 사용방법

Visual Studio 2008에서 ActiveX COM(Component Object Model) DLL(Dynamic Link Library)을 사용하는 방법을 알아보자.
COM은 일반적인 컨트롤(control)과는 다르게 움직인다. 통상적인 컨트롤은 핸들(HWND: handle)을 얻어 메시지(SendMessage, GetMessage: message)를 이용해 반응을 한다. 이와는 다르게 COM이 움직이는 기반은 포인터(pointer)이다[1]. COM 생성시에 포인터를 받고 COM과 통신을 할 때도 함수포인터(function pointer)를 이용한다. COM 속에 있는 클래스(class)와 인터페이스(interface: virtual function table)는 각자 고유한 ID(identifier)가 있다. COM 객체를 생성하려면 이 고유한 ID를 얻어서 생성해야 한다. 클래스 ID는 CLSID(CLaSs ID)라 부르고 인터페이스 ID는 UUID(Universally Unique ID)라 한다. 또한, COM을 사용하기 전에 반드시 컴퓨터에 등록을 해야 한다. 아래에 in-process sever(server와 client가 같은 컴퓨터에 있다.) 관점으로 설명한다.

- 먼저 "C:\WINDOWS\system32" 폴더에 DLL을 복사한다.
- 명령어 "regsvr32 test.dll"을 이용해 등록한다. "실행"이나 "명령 프롬프트"를 이용하면 명령어를 OS에 입력할 수 있다.
- 등록이 성공하면 test.dll의 DllRegisterServer 성공이란 창이 뜬다.
- 등록을 해제하고 싶으면 "regsvr32 /u test.dll"를 사용하면 된다.
- "regedit"을 이용하면 등록한 COM이 레지스트리(registry)상의 "HKEY_CLASSES_ROOT/CLSID" 아래에 존재하는 것을 확인할 수 있다.

COM 등록이 완료되면 아래 절차에 따르 COM 객체를 생성하면 된다.

1. COM 헤더 파일 생성 및 선언
#import "C:/WINDOWS/system32/test.dll" no_namespace
ActiveX COM은 통상적인 헤더 파일(header file)을 사용하지 않고 위의 구문을 이용해 함수들 정의가 담긴 헤더 파일을 자동생성한다. 이렇게 생성된 포인터를 COM smart pointer라고 한다. 위 구문은 통상적인 헤더 파일을 선언한 것과 동일한 효과를 가지므로 필요한 곳에 헤더 파일 대신에 사용하면 된다.

2. COM 라이브러리 초기화

COM을 제어하는 함수들은 대부분 Co...로 시작하는 것을 기억하자. COM 라이브러리를 초기화하려면 아래 두 함수 중에서 하나를 쓰면 된다.
새로 만든 프로젝트라면 새로운 code인 CoInitializeEx 함수를 써야 한다.
   ::CoInitialize(NULL);   // 옛날 code
혹은
   ::CoInitializeEx(NULL, COINIT_MULTITHREADED);   // 새로운 code
프로그램 시작점(예를 들면 InitInstance 함수 혹은 클래스 생성자(class constructor))에서 한 번만 선언한다.(기억할 것: 쓰레드(thread)당 하나씩 생성) 프로그램이 끝날 때(예를 들면 ExitInstance 함수 혹은 클래스 파괴자(class destructor))는 아래를 반드시 호출해야 한다.
   CoUninitialize();

3. COM ID 얻기

COM ID를 얻으려면 아래 code를 사용한다.
   HRESULT nResult;
   CLSID TestID;
   nResult = ::CLSIDFromProgID(OLESTR("test.SmartClass.1"), &TestID);
   if (nResult != S_OK) return FALSE;
위 code를 실행하려면 ProgID(program ID)를 알아야 한다. ProgID는 "regedit"을 이용해 "test.dll"(예를 든 ActiveX COM DLL 이름)을 검색하면 레지스트리에서 ProgID 정보를 찾을 수 있다. ProgID의 형식은 "라이브러리명.객체명.버전"이다. 버전은 생략할 수 있다.

4. COM 인스턴스(instance) 생성

COM smart pointer가 _SmartClass로 선언되었기 때문에(ProgID의 객체명에 '_'를 붙여 컴파일러가 자동생성한다.) 아래 code를 실행하면 된다.
   _SmartClass *ptr;
    nResult = ::CoCreateInstance(TestID, NULL, CLSCTX_INPROC_SERVER, __uuidof(_SmartClass), (LPVOID *) &ptr);

5. COM 사용

VS2008에 있는 "정의로 이동" 기능(_SmarClass 위치로 가서 마우스의 오른쪽을 클릭)을 사용하면 임시로 생성된 TLH(Type Library Header)를 볼 수 있다.

6. COM 라이브러리 해제

위에서도 설명했듯이 해당 쓰레드에서 COM 사용이 끝나면 반드시 아래 code를 호출해야 한다.
   CoUninitialize();
이런 복잡한 과정(COM 사용법 중에서는 가장 쉬운 방법)을 거쳐서 써야하는 COM이 왜 아직까지 살아남아 있을까? 왜냐하면 COM은 플랫폼(platform)에 독립적으로 설계되기 때문에 굉장히 다양한 곳에서 code 변경없이 사용할 수 있기 때문이다.

[참고문헌]
[1] J. Glatt, "COM in plain C," CodeProject, March 2006.

2010년 10월 6일 수요일

CFormView에서 컨트롤에 초점주기

CFormView에 만든 특정한 컨트롤(control)에 초점(focus)을 주려면 아래 방법을 이용하면 된다. 아래 code에서 초점을 주려는 컨트롤은 CWnd을 부모로 하는 class라고 생각한다.

1. CWnd::Focus 함수 이용

그냥 원하는 위치에서 wnd.Focus()를 호출하면 된다. 여기서 wnd는 컨트롤의 이름이다.

2. CFormView::Focus 함수 이용

CWnd::Focus 함수를 이용해도 초점 설정이 안되면 CFormView의 멤버 함수(member function) 안에 아래 code를 삽입해야 한다.
CWnd wnd;
m_hWndFocus = wnd.GetSafeHwnd();
SetFocus();

2010년 10월 5일 화요일

화면갱신시 깜박임 줄이기

1. double buffering

위의 첨부링크를 참고하면 된다. 쉽게 설명하면 먼저 Memory DC(Device Context)에 화면을 사용할 내용을 먼저 그리고 다 그린 후에 Screen DC에 복사하면 깜박임이 줄어든다.

2. Clip Children, Clip Siblings

Dialog 기반이면 간단히 dialog 속성에서 위의 항목들을 "True"로 설정하면 깜박임이 줄어든다. 대화상자를 만들 때 자식창과 형제창은 잘리도록 대화상자를 구성하기 때문이다.

2010년 10월 4일 월요일

CEdit에 숫자입력만 될 때

분명히 DDX_TEXT 함수에도 double이 입력되고 모든 것이 문제가 없는데도 CEdit에 숫자만 입력가능하다면 CEdit 컨트롤(control)을 확인해야 한다.
void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, double& value);
CEdit의 속성 중에서 "Number"에 대한 속성이 "True"이면 당연히 숫자만 입력된다. "Number" 속성을 "False"로 바꾸면 숫자이외의 문자도 입력할 수 있다.

2010년 10월 1일 금요일

예쁜 메뉴 - NewMenu

[그림 1] NewMenu의 실행 모습(출처: podetti.com)

응용프로그램의 frame window, toolbar, statusbar, menu, dialog 등을 예쁘게 꾸미려면 Bruno Podetti가 만든 NewMenu를 사용하면 된다.

1. CMainFrm 클래스(class)의 부모 클래스를 CFrameWnd -> CNewFrameWnd으로 바꾼다.
class CMainFrame : public CNewFrameWnd
{
...
}

2. CMainFrm 클래스의 컨트롤용 멤버 변수(member variable for controls)를 CStatusBar -> CNewStatusBar, CToolBar -> CNewToolBar로 바꾼다.
protected: // 컨트롤 모음이 포함된 멤버입니다.
CNewStatusBar m_wndStatusBar;
CNewToolBar m_wndToolBar;

3. CMainFrm 클래스의 소스 파일(source file)인 "MainFrm.cpp"로 가서 바꾸기 기능을 이용해 CFrameWnd -> CNewFrameWnd으로 바꾼다.

4. OnCreate 함수에 아래 code를 추가한다.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...

m_DefaultNewMenu.LoadToolBar(IDR_MAINFRAME);

// TODO: 도구 모음을 도킹할 수 없게 하려면 이 세 줄을 삭제하십시오.
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);

return 0;
}

5. 응용프로그램의 InitInstance 함수로 가서 아래 code를 추가한다.
BOOL CAntPhaseApp::InitInstance()
{
...
AddDocTemplate(pDocTemplate);

// Set the drawing style of all menus to XP-Mode or STYLE_ORIGINAL
CNewMenu::SetMenuDrawMode(CNewMenu::STYLE_XP_2003);
CNewMenu::SetGloomFactor(0);

// 표준 셸 명령, DDE, 파일 열기에 대한 명령줄을 구문 분석합니다.
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);

...
}

SetMenuDrawMode 함수는 NewMenu를 다양한 색깔로 그릴 수 있도록 옵션을 선택한다. SetGloomFactor 함수는 toolbar의 비트맵(bitmap)의 흐린 정도를 설정한다.

6. toolbar의 색깔을 하이컬러(high color)로 만들려면 더 복잡한 과정을 거쳐야 한다.

1) 먼저 "리소스 뷰"를 이용해서 Bitmap으로 toolbar용 비트맵을 읽어들인다. 예를 들어 이 비트맵의 리소스(resource) 이름을 "IDR_TOOLBAR256"이라 한다.

2) "MainFrm.cpp" 파일 상단에 아래의 정적 변수(static variable)를 추가한다.
static WORD ToolId[] = { IDR_TOOLBAR256,
16, 15,
ID_FILE_NEW,
ID_FILE_OPEN,
ID_FILE_SAVE,
ID_EDIT_CUT,
ID_EDIT_COPY,
ID_EDIT_PASTE,
ID_FILE_PRINT,
ID_APP_ABOUT,
NULL};

3) "MainFrm.cpp" 파일에 있는 OnCreate 함수에 아래 code를 추가한다.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CNewFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("도구 모음을 만들지 못했습니다.\n");
return -1;      // 만들지 못했습니다.
}
m_wndToolBar.SetWindowText(_T("기본동작 도구모음"));
m_wndToolBar.LoadHiColor(MAKEINTRESOURCE(IDR_TOOLBAR256));

if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
 sizeof(indicators)/sizeof(UINT)))
{
TRACE0("상태 표시줄을 만들지 못했습니다.\n");
return -1;      // 만들지 못했습니다.
}

m_DefaultNewMenu.LoadToolBar(ToolId, RGB(192, 192, 192));

// TODO: 도구 모음을 도킹할 수 없게 하려면 이 세 줄을 삭제하십시오.
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);

return 0;
}

응용프로그램(Application Program)의 캡션(Caption) 자동설정 기능 끄기

MFC의 응용프로그램 캡션(caption or title) 자동설정 기능 때문에 파일을 프로그램으로 불러오면 응용프로그램의 캡션이 자동적으로 바뀐다. 편하기는 하지만 경우에 따라 이 기능이 필요하지 않을 때도 있다. 이때는 CMainFram 클래스의 PreCreateWindow 함수에 아래 code를 추가하면 된다.
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// Remove the automatic title option
cs.style &= ~FWS_ADDTOTITLE; 

if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: CREATESTRUCT cs를 수정하여 여기에서
//  Window 클래스 또는 스타일을 수정합니다.

return TRUE;
}

2010년 9월 1일 수요일

갑자기 VS2008 컴파일시 LNK2001 Error가 뜬다면...

LNK2001: ... 외부 기호를 확인할 수 없습니다.
LNK1120: 1개의 확인할 수 없는 외부 참조입니다.

혹은 디버그 모드에서 작업하고 있었으면, Microsoft Visual C++ Debug Library - Debug Assertion Failed!의 경고창이 뜰 수 있다. 문제가 없다고 생각한 프로젝트가 위와 같은 LNK2001이나 LNK1120 error가 뜬다면 당황하지 말고 아래와 같이 속성창을 확인하면 됩니다.

1. 프로젝트의 속성 페이지 대화 상자를 엽니다. 자세한 내용은 방법: 프로젝트 속성 페이지 열기를 참조하십시오.
2. 구성 속성 노드를 확장합니다.
3. 일반 속성 페이지를 클릭합니다.
4. 문자 집합 속성을 "멀티바이트 문자 집합 사용"으로 변경합니다.

위와 같은 문제가 발생하는 이유는 이전에 작성한 DLL이나 함수는 MBCS(Multi-Byte Character Set)로 작성되어 있고 현재의 프로젝트는 unicode(프로젝트를 새로 만들면 기본속성은 unicode가 된다)로 작성되었기 때문이다. 이 문제를 해결하려면 이전에 작성한 DLL이나 함수를 모두 unicode로 바꾸던가 현재 작성할 프로젝트를 MBCS로 하던가를 결정해야 한다. 물론 선택은 프로그래머가 해야 한다.
"멀티바이트 문자 집합 사용"으로 설정한 경우의 문제점은 XP 형태의 공용컨트롤(common controls)이 사라지고 예전에 쓰였던(XP 이전의) 공용컨트롤이 다시 나타나게 된다. 다시 XP 형태의 공용컨트롤이 나오게 하려면 "StdAfx.h"를 수정해야 한다. 파일 "StdAfx.h" 아래를 보면 #ifdef _UNICODE로 시작하는 구문이 보인다.
#ifdef _UNICODE
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#endif

이 #ifdef _UNICODE 구문을 아래와 같이 삭제하면 원래의 XP 형태 공용컨트롤이 다시 나타난다.
//#ifdef _UNICODE
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
//#endif

2010년 8월 18일 수요일

하드웨어 보안 경고

"보안설정에 의해 이동형 저장장치를 사용할 수 없습니다."라는 창이 뜨면 아래 과정을 확인해야 한다.

1. 현재 사용자 계정이 그룹 "Administrators"에 속해 있는가?

[그림 1] 사용자 계정 실행 모습

확인하는 방법은 "시작->실행"에 가서 "control userpasswords2"를 입력하면 된다. 그러면 [그림 1]과 같은 "속성창"이 뜬다. 그룹이 "Administrators"가 아니면 속성 단추를 눌러서 수정하면 된다. 수정 방법은 다음과 같다: 속성 단추를 누르면 "등록정보창"이 나온다. "그룹 등록" 탭을 누른 후 "기타(0)" 라디오 단추에서 "Administrators"를 선택하면 된다.

2. 그래도 안 되면 혹시 보안 프로그램이 설치되어 있는가 확인한다.

제대로 생각도 하지 않고 설치한 보안 프로그램에 의해 이동형 저장장치가 접근불가할 수가 있다. 유일한 방법은 설치한 보안 프로그램을 제거하는 것이다. 애석하게도 대부분의 보안 프로그램은 그냥 제거가 되지 않는다. 적절한 매개변수를 프로그램에 전달해야 삭제가 된다. 예를 들면 하드디스크상에 "C:\Windows\Nics"이란 폴더가 존재하면 보안 프로그램이 설치된 것이다. 이를 제거하려면 "시작->실행"에 가서 "C:\Windows\Nics\Uninst.exe -Dlnics27exc"를 입력해야 한다.

2010년 6월 2일 수요일

VS2008에서 CRichEditCtrl::GetSelText 버그

MBCS와 unicode를 같이 쓰게 되면 CRichEditView 혹은 CRichEditCtrl에서 문제가 발생할 수 있다. GetSelText 버그인 경우는 첨부링크를 참고하자.
첨부링크의 핵심적인 내용은
LPTSTR lpsz = strText.GetBufferSetLength((cr.cpMax - cr.cpMin + 1) * sizeof(TCHAR));
LPTSTR lpsz = strText.GetBufferSetLength((cr.cpMax - cr.cpMin + 1) * 2); 
로 바꾸는 것이다.

2010년 5월 31일 월요일

_CtrlsValidHeapPointer(pUserData) Debug Assertion 해결법

대부분의 경우 메모리 문제때문에 생긴다. 메모리 할당과 해제에 문제가 없는지 확인한다.
다른 문제가 없다면 debug와 release용 DLL 혹은 LIB를 섞어쓴 것을 의심해야 한다. 특히 VS2008은 debug와 release를 명확히 구분하므로 섞어쓴 경우  _CtrlsValidHeapPointer(pUserData) debug assertion을 표시한다.

2010년 5월 30일 일요일

다국어 지원 위해 반드시 Unicode 사용

VS2008을 쓰니 이제 개발도 유니코드(Unicode)로 해야겠다. Unicode(wide character: wchar_t) 체계에서는 모든 문자(영어 혹은 한글)는 2 bytes라는 것만 기억하면 되겠다.

[유니코드 선언과 사용]
1. 문자변수 선언: TCHAR

2. 문자열변수 선언: LPCTSTR, LPTSTR, TCHAR *

3. 문자열 정의: _T("...")

4. 문자열 함수: _tcs...()
   - _tcslen: 문자열의 요소갯수를 반환. ANSI인지 Unicode인지 구별하지 않고 사용한 문자열의 요소갯수(byte수가 아님)를 알려줌.
   - 요수갯수는 문자열을 구성하는 요소들(char, TCHAR, or wchar_t)이 몇 개인가이고 byte수는 문자열이 차지하는 실제 메모리 공간의 수를 뜻함.
   - sizeof(TCHAR):  문자의 byte수를 알려줌. ANSI이면 1 byte, Unicode이면 2 bytes.
   - strlen: 문자열의 byte수를 반환함.

5. MBCS(Multi-Byte Character Set)와 Unicode의 변환
   - MBCS to Unicode: mbstowcs(...) or MultiByteToWideChar(...)
   - Unicode to MBCS: wcstombs(...) or WideCharToMultiByte(...)
   - USES_CONVERSION 선언후 A2W(...) or W2A(...) 사용

[유니코드 함수]
1. 유니코드를 지원하지 않는 함수: 이 함수 입력은 반드시 ASCII가 되어야 함, _T("...")로 정의하면 안 됨
   - GetProcAddress()

[참고문헌]

VS2008은 Class Wizard가 없구나.

예전 VS2003부터 없어졌단다. VS2008에서 class wizard없이 message map을 다루는 방법은 첨부링크에 있다. 쉽게 말하면, message map을 연결하기 원하는 클래스로 가서 마우스의 오른쪽을 클릭한 후 "속성" 항목을 누른다. 그러면 "속성창"이 떠서 이 창에 입력하면 된다. "속성창"은 항목별로 구분되어 있다.
  • "속성창 -> 속성"은 클래스 속성 자체를 변경할 수 있다.
  • "속성창 -> 메시지"에는 해당 클래스에 Windows message map을 연결할 수 있는 기능이 있다.
  • "속성창 -> 이벤트"는 클래스 바깥에서 발생한 이벤트(event)를 잡는 COMMAND나 UPDATE_COMMAND_UI 함수를 설정할 수 있다.
  • "속성창 -> 재정의"에서는 현재 클래스의 부모 클래스 기능을 재정의할 수 있다.

class member variable을 추가하려면 "클래스 뷰"로 가서 마우스의 오른쪽 클릭후 "추가 -> 변수 추가"를 누르면 된다.
class wizard를 다시 보고 싶으면 VS2010을 사용해야 한다. MS도 class wizard의 중요성을 다시 인식한 것인지 VS2010부터는 다시 부활했다.

2010년 5월 28일 금요일

#pragma omp for 사용시 주의점

OpenMP(Open Multi-processing)는 사용이 매우 쉬우나 프로그램 작성시 아래를 주의해야 한다.

1. for 내부에 사용하는 함수는 OpenMP-safe function이 되어야 한다.
   - 내부 사용함수가 global variable 등을 공유해서 사용하면 다른 결과를 낼 수 있으므로 절대 global variable에 연관된 함수를 쓰면 안됨

2. for 내부에 사용할 수 없는 연산자가 있다.
   - +=, -=, *=, /= 등과 같은 축적연산자가 for index와 연관된 경우 실행순서에 따라 다른 값이 출력될 수 있음 -> 절대 사용하면 안됨
   - 굳이 for index와 관계된 축적연산자를 사용하려면 reduction을 사용해서 #pragma omp for reduction(...)을 구성해야 함