2008/12/29

DISKPART 를 이용한 HDD 숨기기

Diskpart는 명령행 프로그램으로 HDD의 partition 을 관리하는 프로그램이다.

(MSDN : http://msdn.microsoft.com/en-us/library/bb905593.aspx)


Diskpart 지원 명령어

    ADD         - 단순 볼륨에 미러를 추가합니다.

    ACTIVE      - 현재 기본 파티션을 활성 부팅 파티션으로 표시합니다.

    ASSIGN      - 선택한 볼륨에 드라이브 문자 또는 탑재 지점을 할당합니다.

    BREAK       - 미러 집합을 나눕니다.

    CLEAN       - 디스크에서 구성 정보 또는 모든 정보를 삭제하고, 디스크를 닫습니다.

    CONVERT     - 서로 다른 디스크 형식으로 변환합니다.

    CREATE      - 볼륨 또는 파티션을 만듭니다.

    DELETE      - 개체를 삭제합니다.

    DETAIL      - 개체 정보를 제공합니다.

    EXIT        - DiskPart 끝내기

    EXTEND      - 볼륨을 확장합니다.

    HELP        - 명령 목록을 인쇄합니다.

    IMPORT      - 디스크 그룹을 가져옵니다.

    LIST        - 개체 목록을 인쇄합니다.

    INACTIVE    - 현재 기본 파티션을 비활성 파티션으로 표시합니다.

    ONLINE      - 현재 오프라인으로 표시된 디스크를 온라인으로 만듭니다.

    REM         - 아무 작업도 하지 않습니다. 스크립트를 설명하는데 사용됩니다.

    REMOVE      - 드라이브 문자 또는 탑재 지점 할당을 제거합니다.

    REPAIR      - RAID-5 볼륨을 복구하십시오.

    RESCAN      - 디스크 및 볼륨을 다시 검색합니다.

    RETAIN      - 단순 볼륨에 보유자 파티션을 만듭니다.

    SELECT      - 포커스를 개체로 이동합니다.


이 Diskpart 프로그램을 이용하여 파티션에 할당한 드라이브 문자를 삭제 및 재 할당을 할 수 있다.

삭제를 하면 해당 파티션에대한 사용을 하지 못한다.


드라이브 문자 삭제 방법

    0. Volume 목록 확인

        DISKPART>list volume

    1. 삭제하고자 하는 Volume 선택

        DISKPART>select volume 2

    2. 드라이브 문자 삭제

        DISKPART>remove letter e


드라이브 문자 할당 방법

    0. Volume 목록 확인

        DISKPART>list volume

    1. 삭제하고자 하는 Volume 선택

        DISKPART>select volume 2

    2. 드라이브 문자 할당

        DISKPART>assign letter e


아래 화면은 문자를 삭제하고 할당하는 예를 보여주는 화면이다.

2008/12/27

CTime 과 CTimeSpan 으로 시간 연산하기 (시간차 계산)

시각을 관리하는 CTime 클래스와 시간을 관리하는 CTimeSpan 을 이용하여 시간을 연산할 수 있다.

CTime 클래스는 +,- 연산자를 지원하는데 - 연산자의 경우 피연산자를 CTime 을 사용하면 두 시각의 시간차를 구할 수 있다.
+,- 연산자와 피연산자로 CTimeSpan 을 사용하면 특정 시각을 기준으로 일정시간 뒤(-)나 앞(+)의 시각을 계산할 수 있다.



// from MSDN : http://msdn.microsoft.com/en-us/library/3a34945y.aspx
CTime t1(1999, 3, 19, 22, 15, 0); // 10:15 PM March 19, 1999
CTime t2(1999, 3, 20, 22, 15, 0); // 10:15 PM March 20, 1999
CTimeSpan ts = t2 - t1; // Subtract 2 CTimes
ATLASSERT(ts.GetTotalSeconds() == 86400L);
ATLASSERT((t1 + ts) == t2); // Add a CTimeSpan to a CTime.
ATLASSERT((t2 - ts) == t1); // Subtract a CTimeSpan from a CTime.


// t1과 t2의 시간차
ts.GetDays(); // 두시각의 날짜 차이
ts.GetHours(); // 두시각의 시간 차이 ( –23 ~ 23 )
ts.GetTotalHours(); // 날짜를 시간으로 환산한 두 시각의 총 시간 차이
ts.GetMinutes(); // 두시각의 분 차이 (–59 ~ 59)
ts.GetTotalMinutes(); // 날짜와 시간을 분으로 환산한 두 시각의 총 분 차이
ts.GetSeconds(); // 두 시각의 초 차이 (–59 ~ 59)
ts.GetTotalSeconds(); // 날짜 시간 분을 초로 환산한 두 시각의 총 초 차이


// CTimeSpan 활용하기 : http://msdn.microsoft.com/en-us/library/h7zw4wy1.aspx
CTimeSpan ts1; // Uninitialized time value
CTimeSpan ts2a(ts1); // Copy constructor
CTimeSpan ts2b = ts1; // Copy constructor again
CTimeSpan ts3(100); // 100 seconds
CTimeSpan ts4(0, 1, 5, 12); // 1 hour, 5 minutes, and 12 seconds


// CTime 에 시간 더하기
t1 += CTimeSpan( 100 ); // ti 에 100초 더하기

// CTime 에 하루 더하기
t1 += CTimeSpan( 1, 0, 0, 0 ); // CTimeSpan( 날짜, 시간, 분, 초 )


Original Post : http://neodreamer-dev.tistory.com/231

2008/12/25

std::string 의 날짜를 CTime에 넣기

MySQL의 DATE 함수에 의해 얻어진 std::string 문자열("YYY-MM-DD")을 CTime에 넣기.

        // "1999-01-01"
// "0123456789"
std::string d = "1999-01-01";

CTime time(
atoi( d.substr(0, 4).c_str() ), // Year
atoi( d.substr(5, 2).c_str() ), // Month
atoi( d.substr(8, 2).c_str() ), // Day
0, 0, 0 /* Time */ );


Original Post : http://neodreamer-dev.tistory.com/229

2008/12/23

CDialogBar 를 CDialog 처럼 사용하기

이 내용은 다음의 사이트를 참고하여 직접 작업을 해 보면서 작성한 글임.

http://myhome.hanafos.com/~kukdas/doc/mfc/dialogbar.html

http://www.charmzine.com/blog/charmzine/17


1. 리소스에 다이얼로그 추가

다이얼로그 리소스를 추가하고 아이디를 부여한다.

DialogBar로 사용하기 위해 Style 속성을 Child로, Border 속성을 None 으로 변경한다.




2. 클래스 생성

추가된 다이얼로그 리소스를 기반으로 클래스를 생성한다.

이때 Base 클래스가 CDialogBar가 없기 때문에 CDialog 를 상속 받아서 생성한다.




3. 기반(Base) 클래스 변경

생성된 클래스에서 CDialog 를 CDialogBar로 변경한다.

생성자 부분의 기반 클래스 생성자 호출 부분은 주석처리 한다.

    IMPLEMENT_DYNAMIC(CMyBar, CDialogBar)

CMyBar::CMyBar(CWnd* pParent /*=NULL*/)
/*: CDialogBar(CDialogBar::IDD, pParent)*/
{
}

CMyBar::~CMyBar()
{
}

void CMyBar::DoDataExchange(CDataExchange* pDX)
{
CDialogBar::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CMyBar, CDialogBar)
END_MESSAGE_MAP()




4. DDX/DDV를 사용하기 위해 메세지 처리 함수 추가하고 WM_INITDIALOG 와 매핑시킨다.

    // Header
afx_msg LRESULT OnInitDialog(WPARAM, LPARAM);

// Source
BEGIN_MESSAGE_MAP(CMyBar, CDialogBar)
:
ON_MESSAGE( WM_INITDIALOG, OnInitDialog)
:
END_MESSAGE_MAP()

LRESULT CMyBar::OnInitDialog(WPARAM wParam, LPARAM lParam)
{
if ( !HandleInitDialog(wParam, lParam) || !UpdateData( FALSE ) )
{
TRACE0("Warning: UpdateData failed during dialog init.\n");
return FALSE;
}

return TRUE;
}




5. 메인 프레임에서 생성하기

생성된 클래스의 헤더파일을 메인프레임에 포함시켜 주고 OnCreate 에 다이얼로그바를 생성한다.

    // Header
#include "MyBar.h"

CMyBar m_wndDialogBar;

// Source
if ( !m_wndDialogBar.Create( this, IDD_MYBAR,
CBRS_LEFT | CBRS_TOOLTIPS | CBRS_FLYBY,
IDD_MYBAR ))
{
TRACE0("Failed to create dialogbar");
return -1;
}




6. 버튼 활성화 시키기

DialogBar에 올려진 버튼은 ON_BN_CLICKED 이벤트를 매핑 시켜 주어도 활성화가 되지 않는다.

ON_UPDATE_COMMAND_UI 이벤트를 매핑 시켜 주어야하는데 이 작업은 수동으로 해야한다.

    // Source
afx_msg void OnUpdateCmdUI(CCmdUI* pCmdUI);

// Header
BEGIN_MESSAGE_MAP(CMyBar, CDialogBar)
ON_UPDATE_COMMAND_UI( IDC_BTN_SEARCH, OnUpdateCmdUI )
END_MESSAGE_MAP()


Original Post : http://neodreamer-dev.tistory.com/228

Firefox 에 MSDN 검색 사이트 추가하기

1. http://mycroft.mozdev.org/ 접속




2. 검색어 MSDN 으로 검색






3. 검색 사이트 선택






4. 등록 완료


Original Post : http://neodreamer-dev.tistory.com/227

2008/12/22

MySQL Connector/C++ 1.0.2 Alpha Library

몇일 전 공개된 MySQL Connector/C++ 1.0.2 Alpha 버전을 컴파일 하여 DLL 과 라이브러리(Static 포함)를 만들었다. 컴파일러 버전은 Visual C++ 2005를 사용하였다.


진행 중인 프로젝트(32bit, 64bit)에 바로 적용을 하여 테스트 해보았는데 크게 문제가 되는게 없어 보였다.

테스트에 사용된 라이브러리는 MySQL 5.0.67 과 함께 컴파일한 라이브러리이다.



MySQL Connector/C++ 1.0.2 Source




With MySQL 5.0.67




With MySQL 5.1.30




Original Post : http://neodreamer-dev.tistory.com/226

MySQL Connector/C++ 1.0.2 Alpha Release

MySQL 의 C++ Connector 가 1.0.2 Alpha 버전을 공개하였다.

이번 버전에서 수정된 내용

MySQL Connector/C++ 1.0.2 Alpha (19. December 2008)

  • Adding test/unit as a basis for general unit tests based on the new test framework, see test/unit/example for basic usage examples (Ulf)

  • Fixed MySQL_PreparedStatement::setBlob() to really work. In the tests there is a simple example of a class implementing sql::Blob. (Andrey)

  • Addition of a new unit test framework for JDBC compliance and regression testing. We now include our JDBC compliance tests in the releases (Lawrin)

  • Implemented MySQL_ResultSetMetaData::getPrecision() and MySQL_Prepared_ResultSetMetaData::getPrecision(),updating example. (Andrey)

  • Fixing bug in FLOAT handling. (Andrey)

  • Fixing bug in getString(): getString() is binary safe now (Andrey), new example. (Ulf)

  • Fixing bugs in MySQL_PreparedStatements: setBigInt() and setDatetime() have decremented the internal column index before forwarding the request. This resulted in double-decrement and wrong internal column index. Typical error message: setString() ... invalid "parameterIndex" (Ulf)

  • Adding PHP script examples/cpp_trace_analyzer.php to filter the output of the debug trace. Please see the inline comments for documentation. This script is unsupported! We do no promise to maintain it. (Ulf)

  • Fixed bugs in MySQL_DatabaseMetaData :all supportsCatalogXXXXX methods were returning `true` and all supportSchemaXXXX methods false, which is not as it should be. Now it is reversed, to be consistent with the rest. (Andrey)

  • Implemented MySQL_PreparedStatement::clearParameters(). (Andrey)

  • Fixed a bug in MySQL_ConnectionMetaData::getColumns() which was performing a cartesian product of the columns in the table times the columns matching columnNamePattern. example/connection_meta_schemaobj.cpp extended to cover the function. (Andrey)

  • Fixed lame bug in MySQL_ConnectionMetaData::getIndexInfo() which did not work because the schema name wasn't included in the query sent to the server. (Andrey)

  • Implemented MySQL_PreparedStatement::setNull(). (Andrey)

  • Reverted implementation of MySQL_DatabaseMetaData::getTypeInfo(). Now unimplemented. In addition, removed cppconn/datatype.h for now till we havea proper implementation of the types.

  • DATE, DATETIME and TIME are now being handled when calling MySQL_PreparedResultSet::getString(), ::getDouble, ::getInt(), ::getLong(), ::getBoolean()

  • Fixed MySQL_PreparedStatementResultSet::getDouble() to return proper value when the underlying type is MYSQL_TYPE_FLOAT. (Andrey)

  • Changed ResultSetMetaData::getColumnDisplaySize(), ::getPrecision(), ::getScale() to return unsigned int instead of signed int. (Andrey)

  • Implemented getScale(), getPrecision() and getColumnDisplaySize() for MySQL_ResultSetMetaData and MySQL_Prepared_ResultSetMetaData. (Andrey)


MySQL Connector/C++ Webpage
Original Post :
http://neodreamer-dev.tistory.com/225

CListCtrl 에서 전체 Row 선택 설정하기

CListCtrl 에서 아이템을 선택하면 아이템 부분만 선택이 되고 SubItem 부분은 선택이 되지 않는데 이때 CListCtrl 에 LVS_EX_FULLROWSELECT 속성을 추가해 주면 SubItem 부분도 선택이 된다.


    m_lstLibrary.SetExtendedStyle( 
m_lstLibrary.GetExtendedStyle()
| LVS_EX_FULLROWSELECT
);


Original Post : http://neodreamer-dev.tistory.com/224

CListCtrl의 Header 비활성화 - 크기 조절 및 클릭 방지

CListCtrl 사용시에 각 컬럼의 크기를 고정해 놓고 사용자가 임의로 크기를 변경하지 못하도록 막을때 사용하면 된다.

이 방법은 윈도우를 사용하지 못하게 하는 방법으로 컬럼헤더에서 클릭이 필요한 경우에는 사용할 수 없다.

// 방법 1
HWND lvHeader;
lvHeader = ::FindWindowEx(m_lstMachine.GetSafeHwnd(),
NULL, _T("SysHeader32"), _T(""));
::EnableWindow(lvHeader, 0);

// 방법 2
CHeaderCtrl* pHeader = (CHeaderCtrl*) m_listctrl.GetDlgItem(0);
::EnableWindow(pHeader->GetSafeHwnd(), 0);

Original Post : http://neodreamer-dev.tistory.com/223

CImageList에 24bit Color 이미지 로딩하기

    CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);

m_pImgList = new CImageList();
m_pImgList->Create(36, 36, ILC_COLOR24, 0, 3);
m_pImgList->Add(&bitmap, RGB(255, 0, 255));

Original Post : http://neodreamer-dev.tistory.com/222

2008/12/18

SQLite3 Version 3.6.7 Library

SQLite3 v3.6.7 Library for C++ Builder






SQLite3 v3.6.7 Libary for Visual C++




Original Post : http://neodreamer-dev.tistory.com/221

강력한 무료 로컬 데이터베이스 시스템 - SQLite 3.6.7 Released!



무료 로컬 데이터베이스인 SQLite 가 3.6.7 버전을 공개하였다.

이번 버전에서 바뀐점은 다음과 같다.


  • Reorganize the Unix interface in os_unix.c

  • Added support for "Proxy Locking" on MacOSX.

  • Changed the prototype of the sqlite3_auto_extension() interface in a way that is backwards compatible but which might cause warnings in new builds of applications that use that interface.

  • Changed the signature of the xDlSym method of the sqlite3_vfs object in a way that is backwards compatible but which might cause compiler warnings.

  • Added superfluous casts and variable initializations in order to suppress nuisance compiler warnings.

  • Fixes for various minor bugs.


제작사 측은 이전 버전중 3.6.6.2 버전 사용자는 업그레이드 필요성이 많지 않지만  3.6.4 에서 3.6.6.1 버전까지 사용자는 3.6.7 로 바꾸는길 권하고 있다.

SQLite 홈페이지
SQLite 다운로드 페이지
Original Post :
http://neodreamer-dev.tistory.com/220

2008/12/13

매력적인 힙 메모리 관리 템플릿 클래스 auto_ptr

new로 생성한 포인터 변수는 반드시 delete로 할당된 메모리를 해제해 주어야 한다.

은 코드나 중간에 실행 경로를 바꾸는 일이 없을 경우에는 처리가 비교적 쉽지만 예외사항을 처리하고 중간에 함수를 빠져나가는
경우가 있을경우 힙 영역에 할당한 메모리 해제에 대하여 신중해야한다. 이럴경우 auto_prt 을 사용하면 편리하다.

MySQL Connector/C++ 을 사용하면서 사용하게 되었는데 아주 놈이다.

사용 방법은 아래와 같다.
std::auto_ptr< 데이터 타입 > variable( 할당할 데이터 포인터 );

std::auto_ptr< int > myInt( new int(5) );


의 구문은 myInt 를 int 형을 가리키는 포인터이며 새로 생성한 int(5)를 가리키고 있다. 이때 생성한 new
int(5) 는 명시적으로 delete로 해제 하지 않아도 함수가 종료되는 시점에 자동으로 delete가 된다.

auto_ptr 은 기본적으로 포이터만 핸들링 할 수 있으며 포인터 배열( new int[5] )의 경우 메모리 해제에 문제가 있다. 그리고 stl 의 container 에는 사용할 수 없다.

auto_ptr 은 기본 생성자및 소멸자 외에 다음과 같은 메소드를 갖고 있다.
auto_ptr::get()
    auto_ptr이 담고 있는 데이터의 포인터를 반환

auto_ptr::operator *
    auto_ptr이 담고 있는 객체

auto_ptr::operator ->
    auto_ptr 이 담고 있는 객체의 멤버에 접근

auto_ptr::operator =
    auto_ptr 이 가리키고 있는 포이터의 소유권 이전 다른 auto_ptr에게 받아오고 넘겨준 auto_ptr 은 갖고 있던 포인터를 해제함.

auto_ptr::release()
    auto_ptr 이 가리키고 있는 포인터를 명시적으로 삭제함.

auto_ptr::reset()
    기존 포인터를 삭제하고 새로운 포인터를 할당한다

Original Post : http://neodreamer-dev.tistory.com/219

2008/12/12

어영부영 뒷걸음질 치다가 버그 잡았다. MySQL Connector/C++ 에 판정승.. ^^*

어제 종일 씨름 했던 PreparedStatement 문제를 해결 하였다.

릴리즈 모드에서는 문제 없이 실행되던 prepared statement 가 디버그에서는 문제가 발생을 하여 디버그에서 릴리즈용 Library을 사용하여 시도를 해보았지만 다른 문제가 발생하였다.

Library를 새로 만들고 해봐도 해결되지 않다가 프로젝트 속성에서 MFC 라이브러리 사용을 정적으로 바꾸니 그제서야 동작을 하였다.

일단 문제 없이 실행이 되어서 계속진행을 할 수 있지만 왠지 찜찜하다. 짬 나는대로 자료 조사를 좀 해봐야겠다

Original Post : http://neodreamer-dev.tistory.com/218

2008/12/11

MySQL Connector/C++ 과 씨름하다 진이 다 빠졌다.

기본 MySQL C API 를 활용하였었는데 PreparedStatement 를 좀 더 깔끔하게 사용하기위해 MySQL Connector/C++을 사용을 시도해 보았다.

커넥션 관리나 질의문을 다루는 것에는 아무런 문제가 없이 잘 활용 할 수 있었으나 PreparedStatement 사용에 있어 문제가 발생하였다.

자꾸만 Error: 2036 (CR_UNSUPPORTED_PARAM_TYPE) 에러가 발생하였다. 같은 코드를 빈 프로젝트를 생성하여 테스트하면 아무런 문제가 없는데 실제 적용을 하려면 문제가 발생하였다.

라이브러리도 새로 만들어보고 디버그로 해보고 릴리즈모드로도 해보고 도대체 원인을 알 수 가 없었다.

조금만 더 지치면 MySQL++ 로 선회 해버릴 것 같다

Original Post : http://neodreamer-dev.tistory.com/217

CString::Format 으로 삽질하다.

CString 의 Format 문 때문에 종일 삽질을 했다.

    const CString INSERT_MODEL =
_T("INSERT INTO MODEL ")
_T(" (")
_T(" `1`,")
_T(" `2`,")
_T(" `3`,")
_T(" `4`,")
_T(" `5`,")
_T(" `6`,")
_T(" `7`,")
_T(" `8`,")
_T(" `9`,")
_T(" `0`")
_T(" ) VALUES (")
_T(" '%s',") // M
_T(" %f, ") // P
_T(" %f, ") // P
_T(" %f, ") // S
_T(" '%s',") // M
_T(" '%s',") // M
_T(" %d, ") // I
_T(" %f, ") // D
_T(" '%s',") // L
_T(" '%s' ") // M
_T(" );");

CString strSQL;
strSQL.Format( INSERT_MODEL
, CString( "g800" ) // '%s',
, 190.999f // %f,
, 89.999f // %f,
, 0.000f // %f,
, _T("") // '%s',
, CString( "" ) // '%s',
, 0 // %d,
, 0 // %f,
, _T("") // '%s',
, CString( "" ) // '%s'
);

AfxMessageBox( strSQL );




정말 문제가 없어보이는 코드인데... (기본이 부족한 것일까?)


문제가 되었던 부분은 36번째 줄의 실수형을 넣어주어야 하는곳에 정수형 0을 넣어준게 문제였다.

정수형 0을 넣고 실행을 하면 아래와 같은 에러 메시지가 출력된다.



실수형으로 (0.0f) 넣고 실행을 하면 아무런 문제가 없이 정상 동작을 하였다

Original Post : http://neodreamer-dev.tistory.com/216

사용자에게 모든 권한 주기


GRAND ALL PRIVILEGES ON *.* TO 'user'@'host';

Original Post : http://neodreamer-dev.tistory.com/215

Command 창에서 스크립트 실행하기

도스창에서 특정 SQL 스크립트 파일을 실행하는 방법이다.
요즘은 데이터베이스를 사용할 일이 많지 않아 자주 사용하는게 아니라서 인지 자꾸 잊어버린다.

C:\mysql\bin>mysql -u root -pPASSWORD DATABASENAME < script.sql

Original Post : http://neodreamer-dev.tistory.com/214

2008/12/09

MySQL 에서 현재 데이터베이스 이름 알아내기

MySQL 에서 핸재 사용중인 데이터베이스 이름을 알아내는 함수로 DATABASE() 를 제공하고 있고 select DATABASE() 하면 데이터베이스 이름을 가져올 수 있다.


Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> select database();
+------------+
| database() |
+------------+
| NULL       |
+------------+
1 row in set (0.00 sec)

mysql> \u mysql
Database changed
mysql> select database();
+------------+
| database() |
+------------+
| mysql      |
+------------+
1 row in set (0.00 sec)

mysql>
Original Post : http://neodreamer-dev.tistory.com/213

2008/12/07

한국정보보호진흥원에서 배포하는 SEED 블럭암호화 알고리즘

한국정보보호진흥원에서는 개인 정보 보호를 위해 1999년 2월에 제작한 블럭암호화 알고리즘 SEED를 배포하고 있다.


요즘 데이터 암호화에 관심이 있어 찾아 보다 알게된 정보이다. 그래서 소스를 받고자 한국정보보호진흥원을 방문해 보았지만 SEED에 대한 설명만 있었다.


소스를 받기위해서는 신청서를 작성하고 관리자의 인증을 거쳐 보내준다 한다. 급한 일이거나 잠깐 테스트 할 경우리면 답답한 일이 아닐 수 없다.


그래서 인터넷에 소스가 올라온 곳을 찾을 수 있었다.


SEED 알고리즘 소스


SEED 블럭암호 알고리즘

SEED 블럭암호 알고리즘 신청 페이지
Original Post :
http://neodreamer-dev.tistory.com/212

C++ Builder 용 SQLite 정적 라이브러리 만들기

이전 포스팅에서 Visual C++ 용 SQLite 정적 라이브러리 만들기에 대한 내용을 올렸었는데 이번에는 C++ Builder 용에 대한 글이다.


Visual C++ 과 크게 다르지는 않다. 프로젝트 생성 및 라이브러리 관련 설정이 빠지고 나머지는 같다.


프로젝트 생성시에 Static Library를 설정하여 프로젝트를 생성한다.

Static Library 프로젝트 생성

Static Library 프로젝트 생성




생성 후 SQLite 소스를 프로젝트에 포함 시킨 후 tclsqlite.c 를 프로젝트에서 제거하고 Conditional defines 에 NO_TCL 을 설정해 준다.

Conditional defines 설정

Conditional defines 설정



Pre-compiled headers 를 사용하지 않음으로 설정하고 프로젝트를 컴파일 한다.

Pre-compiled headers 사용안함 설정

Pre-compiled headers 사용안함 설정




Original Post : http://neodreamer-dev.tistory.com/211

Visual C++ 용 SQLite 정적 라이브러리 만들기

SQLite 를 사용할 때 단일 실행파일에 사용할 정적라이브러리를 만들어 보았다.



먼저 Win32 Consol Application 을 만든다. 프로젝트 생성시 정적 라이브러리로 설정하고 미리 컴파일된 헤더를 사용하지 않는다.



Win32 Consol Project 생성

Win32 Consol Project 생성



응용 프로그램 설정

응용 프로그램 설정





프로젝트 생성 수 SQLite 소스를 프로젝트에 추가 한다. 추가 후 tcl 관련 기능을 사용하지 않기 때문에 tclsqlite.c 파일을 프로젝트에서 삭제하고 전처리기 정의에 NO_TCL 을 설정해 준다.



런타임 라이브러리를 다중 스레드 디버그(Release 의 경우 다중 스레드)로 설정한다.















위의 설정을 끝으로 프로젝트 설정을 마쳤고 이제 컴파일을 하면 된다.



컴파일을 하면 경고 메세지가 많이 나오는데 이 경고 메세지가 거슬린다면 전처리기 정의에 _CRT_SECURE_NO_WARNINGS 를 설정하고 구성 속성 -> C/C++ -> 고급 -> 특정 경고 사용 안 함에 4267;4244;4018;4311;4996;4312 을 설정해 주면 경고 메세지를 없앨 수 있다.




Original Post : http://neodreamer-dev.tistory.com/210

Visual C++ 2005 에서 발생하는 CRT 경고에러 없애기...

Visual C++ 2005 에서는 CRT 함수들에 보다 안전한 처리를 위하여 변수의 크기를 입력하는 함수들이 추가 되었다.

그 예중 하나로 다음과 같은 함수가 있다.

char *strcpy(
char *strDestination,
const char *strSource
);

errno_t strcpy_s(
char *strDestination,
size_t numberOfElements,
const char *strSource
);



경고를 없애려면 이전글에서 언급했던대로 #pragma warning(disable:4996) 를 선언해 주거나 문제가 되는 함수들을 뒤에 "_s" 가 붙은 함수로 바꿔 주면 된다.

하지만 많은 함수를 변경해야 한다면 큰일이 아닐 수 없다.

한번에 깨끗이 없앨 수 있는데 이는 _CRT_NONSTDC_NO_WARNINGS 를 선언해 주면 된다.
하지만 소스상에 선언을 하면 적용이 제대로 되지 않고 Project의 전처리기에 선언을 해 주면 경고 메세지가 나오지 않는다

Original Post : http://neodreamer-dev.tistory.com/209

2008/12/03

MySQL Connector/C++ 을 이용한 간단한 테스트 소스

MySQL Connector/C++ 을 이용하여 간단하게 데이터 베이스 작업을 한 소스이다.

JDBC를 다루었던 경험이 있다면 정말 쉽게 MySQL Connector/C++ 을 이용할 수 있을 것 같다.

설명을하자면 쓸데 없는 글만 늘어 놓을 것 같으니 직접 소스를 보면 한 눈에 들어올 것이다.


    try
{
// Driver 인스턴스 가져오기
m_pDriver = sql::mysql::MySQL_Driver::Instance();

if ( m_pDriver )
{
m_pConn = m_pDriver->connect( "tcp://127.0.0.1", "root", "");

if ( m_pConn )
{
// Statement 생성
sql::Statement *pStmt = m_pConn->createStatement();
sql::ResultSet *res = NULL;

// 데이터 베이스 선택
pStmt->execute( "USE mysql" );
{
// 질의문 수행
res = pStmt->executeQuery( "SELECT host FROM user" );

// 질의결과 탐색
while( res->next() )
{
// 컬럼 데이터 가져오기
std::string host = res->getString( "host" );
TRACE( "%s\n", host.c_str() );
}

// 질의 결과 셋 해제
delete res;
}

// 데이터 베이스 생성
pStmt->execute( "CREATE DATABASE IF NOT EXISTS test" );

// 데이터 베이스 선택
pStmt->execute( "USE test" );

string strQuery;

// 테이블 스키마
strQuery = "CREATE TABLE IF NOT EXISTS member ("
" NAME CHAR(50) NOT NULL PRIMARY KEY,"
" NICK CHAR(50) NULL,"
" AGE INT NOT NULL"
")"
;

// 테이블 내용 삭제
pStmt->execute( "DELETE FROM member" );

// 테이블 생성
pStmt->execute( strQuery );
{
// Insert 문
strQuery = "INSERT INTO member ( name, nick, age )"
" VALUES ('a', 'aa', 10)";

// 레코드 삽입
pStmt->executeUpdate( strQuery );

// 삽입된 레코드 수 가져오기
int nResult = pStmt->getUpdateCount();
TRACE( "Inserted row(s): %d\n", nResult );
}

// Prepared Statement 사용하기
strQuery = "INSERT INTO member ( name, nick, age )"
" VALUES ( ?, ?, ?)";
sql::PreparedStatement *pPreStmt;
pPreStmt = m_pConn->prepareStatement( strQuery );

char name[100];

for ( int i = 0; i < 100; ++i )
{
sprintf( name, "name%03d\0", i );

// 데이터 바인딩
pPreStmt->setString( 1, name );
pPreStmt->setString( 2, "" );
pPreStmt->setInt( 3, 3 );

// Prepared Statement 수행
pPreStmt->executeUpdate();
}

// Statement 삭제
delete pStmt;
}
}
}
catch (sql::SQLException &e)
{
// 예외처리 - 에러 메시지와 에러 코드를 가져올 수 있다.
std::string err = e.what();
}




2008/12/03 - [Dev Story] - MySQL Connector/C++ 1.0.1alpha is available!
2008/12/02 - [Dev Story/Tips] - MySQL Connector/C++ 1.0.1 Alpha 컴파일 하기


Original Post : http://neodreamer-dev.tistory.com/208

MySQL Connector/C++ 1.0.1alpha is available!

어제 MySQL Connector/C++ 1.0.1alpha 버전의 컴파일에 대한 글을 썼는데 그때는 소스를 소스 관리툴인 Bazaar를 통해서 다운 받았어야 했는데 이제는 mysql 웹페이지에서 정식으로 공개를 하고 있다.

MySQL Connector/C++ 1.0.1 버전이 내부적으로 채택이 되어 MySQL Workbench 등에서 사용되고 있고 하니 많이 안정화가 되어 일반 프로젝트에도 적용을 할 수 있을 정도가 되었나 보다.

Announce 메일 전문 보기


MySQL Connector/C++ Wiki page
http://forge.mysql.com/wiki/Connector_C%2B%2B

MySQL Connector/C++ 1.0.1alpha Download page
http://dev.mysql.com/downloads/connector/cpp/1.0.html
Original Post :
http://neodreamer-dev.tistory.com/207

2008/12/02

MySQL Connector/C++ 1.0.1 Alpha 컴파일 하기

MySQL Connector/C++ 를 사용하기 위해서는 소스를 받아 컴파일을 하여 사용하여야 한다. 이 글에서는 Visual C++ 2005 에서 컴파일 하는 방법을 소개하고자 한다.


소스 내려 받기

MySQL Connector/C++ 은 launchpad(https://launchpad.net/mysql-connector-cpp) 를 통해 볼 수 있으며 Bazaar를 설치하여 다운 받을 수 있다.


bzr branch lp:~mysql/mysql-connector-cpp/trunk


bzr branch lp:~andrey-mysql/mysql-connector-cpp/v1_0_1


이것저것 다 귀찮으면 이 글의 맨 마지막에 첨부한 프로젝트 소스를 사용해도 된다.


소스를 받아서 포함되어 있는 README 파일을 보면 마지막 부분에 보면 Windows 에서 컴파일 하는 방법이 나온다. 그 내용을 참고하여 본인이 수행한 내용을 기준으로 정리해 보았다.


우선 컴파일을 위해서 cmake(http://www.cmake.org) 프로그램을 받아야 한다.


설치판을 받아서 설치해도 되지만 레지스트리 건들고 하는걸 싫어하는 필자같은 분들은 무설치 압축 버전을 받으면 된다.


마지막으로 mysql 5.0 이상이 필요한데 이 또한 설치판이 아니고 무설치 압축판을 받으면 된다.


이상의 준비물을 정리해 보면...


+ Visual Studio 2005


+ CMake 2.4 이상 (2008년 12월 2일 현재 버전 2.6)


+ MySQL 5.0 이상


+ MySQL Connector/C++ 소스 (2008년 12월 2일 현재 1.0.1 Alpha)




Visual Studio 를 제외한 나머지 3개의 압축 파일을 풀어준다. 설명을 편히 하고자 MySQL_Conn_cpp 란 폴더에 풀어 놓은 걸로 하겠다.






먼저 시작메뉴의 Visual Studio 2005 에 있는 "Visual Studio 2005 명령 프롬프트"를 실행하여 작업을 한다.

Visual Studio 2005 명령 프롬프트 창에서 MySQL_Conn_cpp 폴더 아래에 있는 MySQL Connector/C++ 소스 위치(MySQL_Conncpp\v1_0_1)로 이동을 하여 아래의 작업을 수행한다.


1. cmake 경로 설정

cmake 을 어느 곳에서나 실행 할 수 있도록 현재의 path에 추가로 cmake 의 경로를 추가 한다.

E:\...\v1_0_1>set path=%path%;E:\Temp\MySQL_Conn_cpp\cmake-2.6.2-win32-x86\bin


2. mysql 경로 설정

E:\...\v1_0_1>set MYSQL_DIR=E:\Temp\MySQL_Conn_cpp\mysql-5.1.30-win32


3. cmake 컴파일러 설정

Debug 의 경우

E:\...\v1_0_1>cmake -G "Visual Studio 8 2005" -DCMAKE_BUILD_TYPE=Debug


Release 의 경우

E:\...\v1_0_1>cmake -G "Visual Studio 8 2005"


64비트 Debug 의 경우

E:\...\v1_0_1>cmake -G "Visual Studio 8 2005 Win64" -DCMAKE_BUILD_TYPE=Debug


64비트 Release 의 경우

E:\...\v1_0_1>cmake -G "Visual Studio 8 2005 Win64"


4. 컴파일

Debug 의 경우

E:\...\v1_0_1>devenv.com MYSQLCPPCONN.sln /build Debug


Release 의 경우

E:\...\v1_0_1>devenv.com MYSQLCPPCONN.sln /build Release


64비트 버전의 경우 프로젝트 소스를 다른 이름(v1_0_1_x64)의 경로에 압축을 풀어서 수행하였다.


위의 작업을 모두 수행하면 v1_0_1 폴더 아래 driver 폴더에 debug 와 release 폴더가 생기고 그 안에 mysqlcppconn.dll 와 mysqlcppconn.lib 파일이 생긴다.


MySQL Connector/C++ 을 포함시키고자 하는 프로젝트에 Debug 용과 Release 용을 따로 따로 포함을 시켜 주어야 한다. 프로젝트를 Debug에 놓고 Release 용 mysqlcppconn.lib 를 포함 시키면 정삭 동작을 하지 않았다.


아래 프로젝트 소스와 만들어진 결과 물로 DLL 과 LIB를 추가 하였다. win32 에 대해서 접속까지는 테스트를 했는데 그 이상은 아직 테스트 해보지 않았다.


지금 진행중인 프로젝트에 포함 시킬 예정으로 x64까지 테스트 할 계획이다.

결과는 다음 포스팅에서....


MySQL Connector/C++ 1.0.1 Alpha 프로젝트 소스




MySQL Connector/C++ 1.0.1 Alpha 컴파일된 DLL 과 LIB 파일




2008/11/28

강력한 무료 로컬 데이터베이스 시스템 - SQLite 3.6.6.2 Released!



얼마전 릴리즈한 3.6.6 버전을 공개한 후로 버그가 발생해서인지 곧바로 3.6.6.1 과 3.6.6.2 버전이 공개가 되었다.

이번 버전에서 수정된 사항은 다음과 같다.
  • Fix a bug in the b-tree delete algorithm that seems like it might be
    able to cause database corruption. The bug was first introduced in
    version 3.6.6 by check-in [5899] on 2008-11-13.
  • Fix a memory leak that can occur following a disk I/O error.


C++ Builser 와 Visual C++ 용 라이브러리


2008/11/27

작고 빠르고 편한 Open Source XML Parser - RapidXML

XML 데이터를 분석해야 할 일이 있어서 공개 소스로 이루어진 프로젝트를 찾아 보았다.

TinyXML 과  RapidXML 을 찾았는데 둘 중 가볍고 사용하기 편한 RapidXML 을 사용하기로 하였다.

RapidXML 소스를 받으면 4개의 소스 파일로만 이루어 졌다.

rapidxml.hpp
rapidxml_iterators.hpp
rapidxml_print.hpp
rapidxml_utils.hpp

rapidxml_print 는 XML을 출력하는 기능이 포함되어 있고. rapidxml_utils 은 XML 데이터 파일을 읽어들이는 기능을 한다.

기본적인 XML 데이터 탐색을 하기위해서는 rapidxml.hpp 만 포함시키면 된다.

기본적인 사용법은 아래의 소스를 보면 한눈에 알 수 있다.


#include "rapidxml.hpp"
#include "rapidxml_utils.hpp"
using namespace rapidxml;

// XML 문서 데이터를 저장할 변수
vector< TCHAR > xmlData;

// XML 파일 불러오기
basic_ifstream<TCHAR> xmlFile( strFile );
xmlFile.seekg(0, ios::end);
size_t size = xmlFile.tellg();
xmlFile.seekg(0);

xmlData.clear();
xmlData.resize( size + 1);
xmlData[size] = 0;

xmlFile.read( &xmlData.front(), (streamsize)size );

// XML Parsing
xml_document< TCHAR > xmlDoc;
xmlDoc.parse<0>( &xmlData.front() );

TCHAR* Name;
TCHAR* Value;
xml_node< TCHAR >* Item;
xml_node< TCHAR >* SubItem;
xml_attribute< TCHAR >* Attr;

// root 포인터
xml_node< TCHAR >* root = xmlDoc.first_node();

// root 하위 Node 탐색
for ( Item = root->first_node(); Item; Item = root->next_sibling())
{
// Node 이름
Name = Item->name();

// Node 의 Attribute 탐색
for ( Attr = Item->first_attribute(); Attr;
Attr = Attr->next_attribute() )
{
Name = Attr->name(); // Attribute 의 이름
Value = Attr->value(); // Attribute 의 값
}

for ( SubItem = Item->first_node(); SubItem;
SubItem = SubItem->next_sibling() )
{
Name = Attr->name(); // Sub node 의 이름
}
}

RapidXML 홈페이지
TinyXML 홈페이지

Original Post : http://neodreamer-dev.tistory.com/204

2008/11/20

CodeGear RAD Studio IDE Fix Pack 2009 1.0

사용자 삽입 이미지


얼마전 출시한 CodeGear 사의 RAD Studio 2009 의 IDE 버그를 수정하는 프로그램 이다.

곧 Prism 을 포함한 정식 RAD Studio 가 출시되면 해결될 문제들이기는 하겠지만....

출처 및 다운로드 : http://andy.jgknet.de/blog/?page_id=246
Original Post :
http://neodreamer-dev.tistory.com/203

SQLite v3.6.5 Library for C++ Builder, Visual C++

C++ Builder

2008/07/25 - [Dev Story/Tips] - C++ Builder 용 SQLite Library 파일 만들기...







Visual C++

2008/07/23 - [Dev Story/Tips] - Visual C++ 2005 에서 간단하게 SQLite Database 사용하기

강력한 무료 로컬 데이터베이스 시스템 - SQLite 3.6.6 Released!




3.6.6 버전에서 변경된 사항

SQLite official webpage
SQLite Release note
SQLite Download page
Original Post :
http://neodreamer-dev.tistory.com/201

2008/11/13

SQLite v3.6.5 Library for C++ Builder, Visual C++

C++ Builder
2008/07/25 - [Dev Story/Tips] - C++ Builder 용 SQLite Library 파일 만들기...





Visual C++
2008/07/23 - [Dev Story/Tips] - Visual C++ 2005 에서 간단하게 SQLite Database 사용하기

<

Original Post : http://neodreamer-dev.tistory.com/200

강력한 무료 로컬 데이터베이스 시스템 - SQLite 3.6.5 Released!




3.6.5 버전에서 변경된 사항



SQLite official webpage
SQLite Release note
SQLite Download page
Original Post :
http://neodreamer-dev.tistory.com/199

2008/11/11

무료 SVN Server - VisualSVN Server 1.6.2 Released



이번 버전에서 바뀐 내용
  • Updated to Subversion 1.5.4. For further
    . Properly handle explicit mergeinfo added in merge source (r32968, -75)
    . fixed: merging of paths containing spaces (r33641, -44)
    . fixed: regression in mergeinfo-aware merges against 1.5.3 (r33693, -704)
  • Fixed: IP address configuration for server binding can be lost on upgrade.
  • Do not check for occupied TCP port on upgrade if VisualSVN Server configured to listen on specific interfaces.
2008/06/19 - [Dev Story/Tips] - 그림으로 보는 간단한 개발서버 구축하기

2008/06/19 - [Dev Story/Tips] - VisualSVN Server 와 TortoiseSVN을 이용하기

VisualSVN Official website
VisualSVN Server page
VisualSVN Server Download P

Original Post :
http://neodreamer-dev.tistory.com/198

[BCB] 테두리없이 크기조절하기

void __fastcall TfrmMain::OnWMNcHitTest(TMessage &msg)
{
int BorderSize = 2;

TPoint MousePos;
MousePos = Point(msg.LParam & 0xFFFF, (msg.LParam >> 16) & 0xFFFF);
MousePos = ScreenToClient(MousePos);

// Check Border
if (MousePos.x <= BorderSize) msg.Result = HTLEFT;
if (Width - BorderSize <= MousePos.x) msg.Result = HTRIGHT;
if (Height - BorderSize <= MousePos.y) msg.Result = HTBOTTOM;
if (MousePos.y <= BorderSize) msg.Result = HTTOP;

if ((MousePos.x <= BorderSize) && (MousePos.y <= BorderSize))
msg.Result = HTTOPLEFT;
if ((MousePos.x <= BorderSize) && (Height - BorderSize <= MousePos.y))
msg.Result = HTBOTTOMLEFT;
if ((Width - BorderSize <= MousePos.x) && (MousePos.y <= BorderSize))
msg.Result = HTTOPRIGHT;
if ((Width - BorderSize <= MousePos.x) &&
(Height - BorderSize <= MousePos.y))
msg.Result = HTBOTTOMRIGHT;
}

Original Post : http://neodreamer-dev.tistory.com/197

2008/11/10

MS CryptoAPI 를 이용한 SQLite 암호화 사용자 함수 만들기

SQLite 에는 기본적으로 지원하는 암호화 기능이 없다. 별도의 비용을 지불 해야만 암호화 기능을 사용할 수 있다.

그래서 이전에 포스팅한 자료(2008/10/30 - [Dev Story/Tips] - Microsoft CryptoAPI 를 이용한 데이터 암호화

)를 바탕으로 데이터를 암호화 하는 사용자 함수를 만들어 보았다.

//------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "uMain.h"
//------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//------------------------------------------------------------------------
#define ENCRYPT_ALGORITHM CALG_RC4
#define KEYLENGTH 0x00800000

static void EncryptFunc(sqlite3_context *context,
int argc, sqlite3_value **argv)
{
if (argc == 0)
sqlite3_result_error(context, "Error: No Data)", -1);
else if (argc == 1)
sqlite3_result_error(context, "Error: No Password", -1);
else if (argc != 2)
sqlite3_result_error(context, "Error: Invalid param count", -1);
else
{
const unsigned char *pwd;
pwd = (const unsigned char *)sqlite3_value_text(argv[1]);
const unsigned char *src;
src = (const unsigned char *)sqlite3_value_blob(argv[0]);

if ( strlen( pwd ) > 0 )
{
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTHASH hHash = NULL;

// Get the Handle to the default provider
if ( !CryptAcquireContext( &hCryptProv,
NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0 ) )
{
if ( GetLastError() == NTE_BAD_KEYSET )
{
if (!CryptAcquireContext(&hCryptProv,
NULL, MS_DEF_PROV,
PROV_RSA_FULL, CRYPT_NEWKEYSET))
{
// CryptAcquireContext() failed.
sqlite3_result_error(
context,
"Error: CryptAcquireContext()",
-1);
return;
}
}
else
{
// CryptAcquireContext() failed.
sqlite3_result_error(
context,
"Error: CryptAcquireContext()",
-1);
return;
}
}


// Create Hash object
if ( !CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash ) )
{
// Error during CryptCreateHash()
sqlite3_result_error(
context,
"Error: CryptCreateHash()",
-1);
return;
}


// Hash the password
if ( !CryptHashData( hHash, pwd, strlen(pwd), 0 ) )
{
// Error during CryptHashData
sqlite3_result_error(
context,
"Error: CryptHashData()",
-1);
return;
}


// Derive a session key from the hash object
if ( !CryptDeriveKey( hCryptProv, ENCRYPT_ALGORITHM,
hHash, KEYLENGTH, &hKey ) )
{
// Error during CryptDeriveKey
sqlite3_result_error(
context,
"Error: CryptDeriveKey()",
-1);
return;
}


// Encrypt
unsigned long length = strlen(src);
unsigned char *dst = (unsigned char *)malloc(length + 1);
memcpy(dst, src, length + 1 );
if ( !CryptEncrypt( hKey, NULL, TRUE, 0, dst, &length, length ) )
{
// Error during CryptEncrypt
sqlite3_result_error(
context,
"Error: CryptEncrypt()",
-1);
free( dst );
return;
}

sqlite3_result_blob(
context,
dst,
strlen( dst ),
SQLITE_TRANSIENT );
free( dst );
}
}
}
//------------------------------------------------------------------------

static void DecryptFunc(sqlite3_context *context,
int argc, sqlite3_value **argv)
{
if (argc == 0)
sqlite3_result_error(context, "Error: No Data)", -1);
else if (argc == 1)
sqlite3_result_error(context, "Error: No Password", -1);
else if (argc != 2)
sqlite3_result_error(context, "Error: Invalid param count", -1);
else
{
const unsigned char *src;
src = (const unsigned char *)sqlite3_value_blob(argv[0]);
const unsigned char *pwd;
pwd = (const unsigned char *)sqlite3_value_text(argv[1]);

if ( strlen( pwd ) > 0 )
{
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTHASH hHash = NULL;

// Get the Handle to the default provider
if ( !CryptAcquireContext( &hCryptProv, NULL,
MS_ENHANCED_PROV, PROV_RSA_FULL, 0 ) )
{
if ( GetLastError() == NTE_BAD_KEYSET )
{
if (!CryptAcquireContext(&hCryptProv, NULL,
MS_DEF_PROV, PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
// CryptAcquireContext() failed.
sqlite3_result_error(
context,
"Error: CryptAcquireContext()",
-1);
return;
}
}
else
{
// CryptAcquireContext() failed.
sqlite3_result_error(
context,
"Error: CryptAcquireContext())",
-1);
return;
}
}


// Create Hash object
if ( !CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash ) )
{
// Error during CryptCreateHash()
sqlite3_result_error(
context,
"Error: CryptCreateHash()",
-1);
return;
}


// Hash the password
if ( !CryptHashData( hHash, pwd, strlen( pwd ), 0 ) )
{
// Error during CryptHashData
sqlite3_result_error(
context,
"Error: CryptHashData()",
-1);
return;
}


// Derive a session key from the hash object
if ( !CryptDeriveKey( hCryptProv, ENCRYPT_ALGORITHM,
hHash, KEYLENGTH, &hKey ) )
{
// Error during CryptDeriveKey
sqlite3_result_error(
context,
"Error: CryptDeriveKey()",
-1);
return;
}


// Decrypt
unsigned long length = strlen(src);
unsigned char *dst = (unsigned char *)malloc(length + 1);
memcpy(dst, src, length + 1 );
if ( !CryptDecrypt( hKey, NULL, TRUE, 0, dst, &length ) )
{
// Error during CryptEncrypt
sqlite3_result_error(
context,
"Error: CryptDecrypt()",
-1);
return;
}

sqlite3_result_blob(
context,
dst,
strlen( dst ),
SQLITE_TRANSIENT );
free( dst );
}
}
}
//------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
m_pDB = NULL;
}
//------------------------------------------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
if ( m_pDB )
sqlite3_close( m_pDB );
}
//------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
int nRst = sqlite3_open( "test.db", &m_pDB );

if ( nRst != SQLITE_OK )
{
ShowMessage("Cannot open database.");
return;
}

int nResult;
nResult = sqlite3_create_function(m_pDB, "Encrypt", -1,
SQLITE_UTF8, NULL, &EncryptFunc, NULL, NULL);
nResult = sqlite3_create_function(m_pDB, "Decrypt", -1,
SQLITE_UTF8, NULL, &DecryptFunc, NULL, NULL);


sqlite3_stmt* pStmt = NULL;
const char* szChar;

String strTemp;
String strQuery;
strQuery = "SELECT Encrypt('test', '123')";

if ( sqlite3_prepare( m_pDB, strQuery.c_str(),
strQuery.Length(), &pStmt, &szChar ) == SQLITE_OK )
{
int nRow = sqlite3_data_count( pStmt );
int nCol = sqlite3_column_count( pStmt );

const char* col1name = sqlite3_column_name( pStmt, 0 );

int nRowCnt = 0;
if ( sqlite3_step( pStmt ) == SQLITE_ROW )
{
++nRowCnt;

const unsigned char* col1 = sqlite3_column_text( pStmt, 0 );

String strMsg;
strMsg.sprintf(
"ROW %d: %s => %s",
nRowCnt, col1name, col1
);
strTemp.sprintf( "%s", col1 );
ShowMessage( strMsg );
}
}

sqlite3_finalize( pStmt );


strQuery = "SELECT Decrypt('" + strTemp + "', '123')";

if ( sqlite3_prepare( m_pDB, strQuery.c_str(),
strQuery.Length(), &pStmt, &szChar ) == SQLITE_OK )
{
int nRow = sqlite3_data_count( pStmt );
int nCol = sqlite3_column_count( pStmt );

const char* col1name = sqlite3_column_name( pStmt, 0 );

int nRowCnt = 0;
if ( sqlite3_step( pStmt ) == SQLITE_ROW )
{
++nRowCnt;

const unsigned char* col1 = sqlite3_column_text( pStmt, 0 );

String strMsg;
strMsg.sprintf(
"ROW %d: %s => %s",
nRowCnt, col1name, col1
);
ShowMessage( strMsg );
}
}

sqlite3_finalize( pStmt );
}
//------------------------------------------------------------------------

Original Post : http://neodreamer-dev.tistory.com/196

2008/11/09

C++ Builder 2006(Turbo C++) 에서 GDI+ 사용하기

우선 Include 문 보면

#define STRICT
#include <windows.h>
#include <algorithm>
using std::min;
using std::max;
#include <gdiplus.h>

이렇게 사용하도록 나와 있는데 2006 버전의 gdiplus.h 에 이미 unsing 문과 windows.h algorithm 이 이미 포함이 되었기 때문에 필요 없고 2006 버전에서는 gdiplus.h 만 포함시켜주면됩니다.

여기에 STRICT를 선언해 준 부분이 있는 STRICT를 전역으로 설정해 주어야 하는데 그러기 위해서는 프로젝트 옵션의 Conditional define 부분에 STRICT를 선언해 주어야 한다.



///////////////////////////////////////////////////////////////
//Header
// GDIPlus
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;

///////////////////////////////////////////////////////////////
//Source
// Initialize GDI+.
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

// Shutdown GDI+
Gdiplus::GdiplusShutdown(gdiplusToken);

// Using
Gdiplus::Graphics g(Canvas->Handle);


Original Post : http://neodreamer-dev.tistory.com/195

프로그램 중복 실행 방지하기


HANDLE Mutex;

const char ProgMutex[] = "MyApp";

if (( Mutex = OpenMutex(MUTEX_ALL_ACCESS, false, ProgMutex)) == NULL )
Mutex = CreateMutex( NULL, true, ProgMutex );
else
{
MessageDlg( "Already Running", mtError, TMsgDlgButtons() << mbOK, 0 );
return 0;
}

Original Post : http://neodreamer-dev.tistory.com/194

타이틀 바를 드래그 하는 효과내기 (캡션바 없이 폼 드래깅 하기)

프로그램을 만들다 보면 타이틀 바(캡션바)가 없는 프로그램을 만들어야 하는 경우가 있는데 이때 폼의 클라이언트의 특정 부분이나 폼위의 특정 컨트롤이 캡션바 역할을 해야할 때 사용할 수 있는 방법이다.

캡션바가 눌린 것으로 인식하게끔 프로그램에 Message를 보내는 방법

//OnMouseDown
ReleaseCapture();
Perform(WM_SYSCOMMAND, 0xF012, 0 );



//OnMouseDown
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);




클라이언트에서 버튼이 눌러진 걸 탐지하여 캡션바에서 버튼이 눌러진 것 처럼 Message 바꿔치기 하기


class TForm1 : public TForm
{
...
private:
virtual void __fastcall WMNCHitTest(TWMNCHitTest &Message);

BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_NCHITTEST, TWMNCHitTest, WMNCHitTest)
END_MESSAGE_MAP(TForm)
};

void __fastcall TForm1::WMNCHitTest(TWMNCHitTest &Message)
{
TForm::Dispatch(&Message);
if(Message.Result == HTCLIENT)
Message.Result = HTCAPTION;
}

Original Post : http://neodreamer-dev.tistory.com/193

2008/11/01

C++ Builder 2009 Unicode 로 프로젝트 변환시 링크에러 해결 방법

C++ Builder 2009 이전 버전으로 프로젝트를 생성한 프로젝트를 2009 버전으로 바꾸어 Unicode로 전환 할 경우 아래와 같은 에러 메세지를 접할 때가 있다.

[ILINK32 Error] Error: Unresolved external 'wWinMain' referenced from C:\PROGRAM FILES\CODEGEAR\RAD STUDIO\6.0\LIB\C0W32W.OBJ

위와 같은 메세지는 프로젝트를 유니코드로 변환하지 못하는 경우에 발생하는 것으로 보인다. 2009 버전에서 새로운 프로제트를 생성하여 Unicode 로 전화하여 프로젝트 소스를 비교한 결과 차이점이 있었다.

C++ Builder 2009 이전의 프로젝트 소스


#include <vcl.h>
#pragma hdrstop
//----------------------------------------------------------------------
USEFORM("uMain.cpp", frmMain);
//----------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{



C++ Builder 2009 의 프로젝트 소스


#include <vcl.h>
#pragma hdrstop
#include <tchar.h>
//----------------------------------------------------------------------
USEFORM("uMain.cpp", frmMain);
//----------------------------------------------------------------------
WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{



위의 소스에서 보는 것 처럼 "tchar.h" 를 포함시키고 WinMain 함수를 바꾸어 주면 문제 없이 링크가 된다

Original Post : http://neodreamer-dev.tistory.com/192

2008/10/30

Microsoft CryptoAPI 를 이용한 데이터 암호화

SQLite 에는 기본적으로 지원하는 암호화 기능이 없다. 별도의 비용을 지불 해야만 암호화 기능을 사용할 수 있다.

그래서 이전에 포스팅한 자료(2008/10/30 - [Dev Story/Tips] - Microsoft CryptoAPI 를 이용한 데이터 암호화

)를 바탕으로 데이터를 암호화 하는 사용자 함수를 만들어 보았다.

//------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "uMain.h"
//------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//------------------------------------------------------------------------
#define ENCRYPT_ALGORITHM CALG_RC4
#define KEYLENGTH 0x00800000

static void EncryptFunc(sqlite3_context *context,
int argc, sqlite3_value **argv)
{
if (argc == 0)
sqlite3_result_error(context, "Error: No Data)", -1);
else if (argc == 1)
sqlite3_result_error(context, "Error: No Password", -1);
else if (argc != 2)
sqlite3_result_error(context, "Error: Invalid param count", -1);
else
{
const unsigned char *pwd;
pwd = (const unsigned char *)sqlite3_value_text(argv[1]);
const unsigned char *src;
src = (const unsigned char *)sqlite3_value_blob(argv[0]);

if ( strlen( pwd ) > 0 )
{
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTHASH hHash = NULL;

// Get the Handle to the default provider
if ( !CryptAcquireContext( &hCryptProv,
NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0 ) )
{
if ( GetLastError() == NTE_BAD_KEYSET )
{
if (!CryptAcquireContext(&hCryptProv,
NULL, MS_DEF_PROV,
PROV_RSA_FULL, CRYPT_NEWKEYSET))
{
// CryptAcquireContext() failed.
sqlite3_result_error(
context,
"Error: CryptAcquireContext()",
-1);
return;
}
}
else
{
// CryptAcquireContext() failed.
sqlite3_result_error(
context,
"Error: CryptAcquireContext()",
-1);
return;
}
}


// Create Hash object
if ( !CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash ) )
{
// Error during CryptCreateHash()
sqlite3_result_error(
context,
"Error: CryptCreateHash()",
-1);
return;
}


// Hash the password
if ( !CryptHashData( hHash, pwd, strlen(pwd), 0 ) )
{
// Error during CryptHashData
sqlite3_result_error(
context,
"Error: CryptHashData()",
-1);
return;
}


// Derive a session key from the hash object
if ( !CryptDeriveKey( hCryptProv, ENCRYPT_ALGORITHM,
hHash, KEYLENGTH, &hKey ) )
{
// Error during CryptDeriveKey
sqlite3_result_error(
context,
"Error: CryptDeriveKey()",
-1);
return;
}


// Encrypt
unsigned long length = strlen(src);
unsigned char *dst = (unsigned char *)malloc(length + 1);
memcpy(dst, src, length + 1 );
if ( !CryptEncrypt( hKey, NULL, TRUE, 0, dst, &length, length ) )
{
// Error during CryptEncrypt
sqlite3_result_error(
context,
"Error: CryptEncrypt()",
-1);
free( dst );
return;
}

sqlite3_result_blob(
context,
dst,
strlen( dst ),
SQLITE_TRANSIENT );
free( dst );
}
}
}
//------------------------------------------------------------------------

static void DecryptFunc(sqlite3_context *context,
int argc, sqlite3_value **argv)
{
if (argc == 0)
sqlite3_result_error(context, "Error: No Data)", -1);
else if (argc == 1)
sqlite3_result_error(context, "Error: No Password", -1);
else if (argc != 2)
sqlite3_result_error(context, "Error: Invalid param count", -1);
else
{
const unsigned char *src;
src = (const unsigned char *)sqlite3_value_blob(argv[0]);
const unsigned char *pwd;
pwd = (const unsigned char *)sqlite3_value_text(argv[1]);

if ( strlen( pwd ) > 0 )
{
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTHASH hHash = NULL;

// Get the Handle to the default provider
if ( !CryptAcquireContext( &hCryptProv, NULL,
MS_ENHANCED_PROV, PROV_RSA_FULL, 0 ) )
{
if ( GetLastError() == NTE_BAD_KEYSET )
{
if (!CryptAcquireContext(&hCryptProv, NULL,
MS_DEF_PROV, PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
// CryptAcquireContext() failed.
sqlite3_result_error(
context,
"Error: CryptAcquireContext()",
-1);
return;
}
}
else
{
// CryptAcquireContext() failed.
sqlite3_result_error(
context,
"Error: CryptAcquireContext())",
-1);
return;
}
}


// Create Hash object
if ( !CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash ) )
{
// Error during CryptCreateHash()
sqlite3_result_error(
context,
"Error: CryptCreateHash()",
-1);
return;
}


// Hash the password
if ( !CryptHashData( hHash, pwd, strlen( pwd ), 0 ) )
{
// Error during CryptHashData
sqlite3_result_error(
context,
"Error: CryptHashData()",
-1);
return;
}


// Derive a session key from the hash object
if ( !CryptDeriveKey( hCryptProv, ENCRYPT_ALGORITHM,
hHash, KEYLENGTH, &hKey ) )
{
// Error during CryptDeriveKey
sqlite3_result_error(
context,
"Error: CryptDeriveKey()",
-1);
return;
}


// Decrypt
unsigned long length = strlen(src);
unsigned char *dst = (unsigned char *)malloc(length + 1);
memcpy(dst, src, length + 1 );
if ( !CryptDecrypt( hKey, NULL, TRUE, 0, dst, &length ) )
{
// Error during CryptEncrypt
sqlite3_result_error(
context,
"Error: CryptDecrypt()",
-1);
return;
}

sqlite3_result_blob(
context,
dst,
strlen( dst ),
SQLITE_TRANSIENT );
free( dst );
}
}
}
//------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
m_pDB = NULL;
}
//------------------------------------------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
if ( m_pDB )
sqlite3_close( m_pDB );
}
//------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
int nRst = sqlite3_open( "test.db", &m_pDB );

if ( nRst != SQLITE_OK )
{
ShowMessage("Cannot open database.");
return;
}

int nResult;
nResult = sqlite3_create_function(m_pDB, "Encrypt", -1,
SQLITE_UTF8, NULL, &EncryptFunc, NULL, NULL);
nResult = sqlite3_create_function(m_pDB, "Decrypt", -1,
SQLITE_UTF8, NULL, &DecryptFunc, NULL, NULL);


sqlite3_stmt* pStmt = NULL;
const char* szChar;

String strTemp;
String strQuery;
strQuery = "SELECT Encrypt('test', '123')";

if ( sqlite3_prepare( m_pDB, strQuery.c_str(),
strQuery.Length(), &pStmt, &szChar ) == SQLITE_OK )
{
int nRow = sqlite3_data_count( pStmt );
int nCol = sqlite3_column_count( pStmt );

const char* col1name = sqlite3_column_name( pStmt, 0 );

int nRowCnt = 0;
if ( sqlite3_step( pStmt ) == SQLITE_ROW )
{
++nRowCnt;

const unsigned char* col1 = sqlite3_column_text( pStmt, 0 );

String strMsg;
strMsg.sprintf(
"ROW %d: %s => %s",
nRowCnt, col1name, col1
);
strTemp.sprintf( "%s", col1 );
ShowMessage( strMsg );
}
}

sqlite3_finalize( pStmt );


strQuery = "SELECT Decrypt('" + strTemp + "', '123')";

if ( sqlite3_prepare( m_pDB, strQuery.c_str(),
strQuery.Length(), &pStmt, &szChar ) == SQLITE_OK )
{
int nRow = sqlite3_data_count( pStmt );
int nCol = sqlite3_column_count( pStmt );

const char* col1name = sqlite3_column_name( pStmt, 0 );

int nRowCnt = 0;
if ( sqlite3_step( pStmt ) == SQLITE_ROW )
{
++nRowCnt;

const unsigned char* col1 = sqlite3_column_text( pStmt, 0 );

String strMsg;
strMsg.sprintf(
"ROW %d: %s => %s",
nRowCnt, col1name, col1
);
ShowMessage( strMsg );
}
}

sqlite3_finalize( pStmt );
}
//------------------------------------------------------------------------

Original Post : http://neodreamer-dev.tistory.com/196

2008/10/27

TortoiseSVN-1.5.5.14361 Released!!




갑자기 업데이트 주기가 빨라진 것 같다.
얼마전 1.5.4버전으로 업데이트 되었는데 곧바로 1.5.5버전이 나왔다.

이번 버전에서 바뀐점
Version 1.5.5
- BUG: The properties dialog would show the url with backward slashes when
       started from the repository browser. (Stefan)


TortoiseSVN Homepage

TortoiseSVN-1.5.5.14361-win32-svn-1.5.4.msi

TortoiseSVN-1.5.5.14361-x64-svn-1.5.4.msi

Original Post : http://neodreamer-dev.tistory.com/190

2008/10/18

TortoiseSVN-1.5.4.14259 Released!!




1.5.4 버전에서 바뀐점.

- CHG: OpenSSL 0.9.8i with capieng enabled
- BUG: Applying a patch where a context line had UTF-BOMs
       in it failed. (Stefan)
- BUG: Checking out multiple folders from the repository browser failed
       to unescape the target folder. (Stefan)
- BUG: If an url had special chars which needed escaping below the
       repository root, showing the log did not always work. (Stefan)
- BUG: Comparing two revisions sometimes did not work if the url didn't
       exist anymore in HEAD. (Stefan)
- BUG: Diffing/Blaming from TortoiseBlame on merged revisions did not
       work in certain situations. (Stefan)
- BUG: Unescape the target paths when exporting the changed files from
       the file diff dialog. (Stefan)
- BUG: the 'unversioned' overlay for folders didn't show up for some
       unversioned folders. (Stefan)
- BUG: After a "mine before theirs" or "theirs before mine" resolving
       action on the right pane in TortoiseMerge, the Undo would not
       undo correctly. (Stefan)
- BUG: Failures, even GPF in blame and log dialogs when specifying a
       revision range and a peg revision outside that range. (Stefan Fuhrmann)
- BUG: TortoiseMerge sometimes wrongly detected the encoding of files. (Stefan)
- BUG: If a merge conflicted due to added items the progress dialog did not
       count these correctly and the context menu missed items. (Tobias Sch�fer)
- BUG: TortoiseMerge could crash if the font size was set smaller than
       8 pixels. (Stefan)
- BUG: When a cleanup failed, the error message didn't include the svn
       error string. (Stefan)
- BUG: /closeonend was ignored for the (un)lock command. (Stefan)
- BUG: The 'rename' context menu was not available for added files. (Stefan)
- BUG: Entering an URL before non-ascii text in the commit dialog corrupted
       the first chars of the non-ascii text. (Stefan)
- BUG: Blame from the repository browser ignored the diff options. (Stefan)

TortoiseSVN Homepage

TortoiseSVN-1.5.4.14259-win32-svn-1.5.3.msi

TortoiseSVN-1.5.4.14259-x64-svn-1.5.3.msi
LanguagePack_1.5.4.14259-win32-ko.msi
LanguagePack_1.5.4.14259-x64-ko.msi


Original Post : http://neodreamer-dev.tistory.com/189