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