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

2008/10/15

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



3.6.4 버전에서 변경된 사항



  • Add option support for LIMIT and ORDER BY clauses on DELETE and UPDATE statements. Only works if SQLite is compiled with SQLITE_ENABLE_UPDATE_DELETE_LIMIT.

  • Added the sqlite3_stmt_status() interface for performance monitoring.

  • Add the INDEXED BY clause.

  • The LOCKING_STYLE extension is now enabled by default on Mac OS-X

  • Added the TRUNCATE option to PRAGMA journal_mode

  • Performance enhancements to tree balancing logic in the B-Tree layer.

  • Added the source code and documentation for the genfkey program for automatically generating triggers to enforce foreign key constraints.

  • Added the SQLITE_OMIT_TRUNCATE_OPTIMIZATION compile-time option.

  • The SQL language documentation is converted to use syntax diagrams instead of BNF.

  • Other minor bug fixes
SQLite official webpage
SQLite Release note
SQLite Download page

C++ Builder 용 SQLite3.lib



Visual C++ 용 SQLite3.lib

무료 SVN Server - VisualSVN Server 1.6.1 Released




심각한 버그가 있었나 보다. 1.6 버전을 릴리즈 한지 얼마 되지 않아 1.6.1 버전을 릴리즈 하였다.

2008/06/19 - [Dev Story/Tips] - 그림으로 보는 간단한 개발서버 구축하기

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

1.6.1 버전에서 바뀐점


  • SVNPathAuthz short_circuit option is disabled (serious
    authorization problems are encountered).


  • Fixed: installation doesn't recognize the folder where
    the previous version is installed.




VisualSVN Official website
VisualSVN Server page
VisualSVN Server Download

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

2008/10/14

Visual Studio 를 위한 무료 SVN plugin - AnkhSVN

사용자 삽입 이미지

Visual Studio IDE에서 SubVersion 을 사용할 수 있게 해주는 Open source plugin 이다.

프로젝트가 오픈 소스로 진행이 되고 Dialy Build 도 지원하여 매일매일 패치되는 버전을 받을 수도 있다.

Visual Studio의 솔루션 탐색기에 포함되어 파일 아이콘에 변경된 내용이 반영되어 쉽게 버전 관리를 할 수 있다.

무료 SVN Server - VisualSVN Server 1.6 Released




버전관리 프로그램의 하나인 Subversion 를 윈도우 상에서 간단하게 서버 구성할 수 있는 VisualSVN Server가 버전업을 하였다.

2008/06/19 - [Dev Story/Tips] - 그림으로 보는 간단한 개발서버 구축하기

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


1.6 버전에서 바뀐점


  • New: Certificate Management.


  • New: Advanced server binding configuration.

  • New: Simple email notifications hook.

  • New: Subverison hook for checking filename case-sensitivity.

  • New: Logging to the Event Log.


  • New: Commands to create/delete folder in repository.

  • New: Server name configuration.

  • Updated to Subversion 1.5.3. For further details please see:


    http://svn.collab.net/repos/svn/tags/1.5.3/CHANGES

  • mod_auth_digest Apache module is removed from installation.


  • Fixed: VisualSVN Server crashes on folders with chinese characters.

  • Maximize button is available in the hook edit window.

  • Improved error message is logged when service has failed to start during installation.

  • Installation process is continued even if firewall configuration is failed.

  • Do not reset firewall settings on upgrade.

  • Firewall configuration is improved on Windows Vista and Windows Server 2008.


  • Installation of an older version over the newer one is prohibited.

  • Apache and Subversion package versions are displayed during the installation.

  • Existing hooks are marked by bold lines in the Properties/Hooks window.

  • VisualSVN Server properties dialog splited into separate pages

  • SVNPathAuthz short_circuit option is enabled (improve performance on authorization
    intensive operations)



VisualSVN Official website

VisualSVN Server page
VisualSVN Server Download Page
Original Post :
http://neodreamer-dev.tistory.com/185

2008/10/13

MFC 에서 간단하게 DAO 사용하기

MFC 프로그래밍에서 간단하게 DAO를 사용하는 코드이다.

예전에는 자주 사용했지만 현재는 로컬데이터베이스 시스템을 이용할 경우에는 MS-Access 보다는 SQLite를 사용한다.

// For Database
#include <atlbase.h>
#include <afxoledb.h>
#include <atlplus.h>
#include <afxdao.h> // For MDB


////////////////////////////////////////////////////////////////////////////
// Header

#pragma once
#pragma warning(disable: 4995)

class CLibDB
{
public:
CLibDB(void);
virtual ~CLibDB(void);

private:
LPCTSTR strBOOL(BOOL bFlag);
CString strVARIANT(const COleVariant& var, char *pBuf = NULL);
void DisplayDaoException(CDaoException* e);
BOOL IsExistentTable(CDaoDatabase *pDatabase, CString strTableName);

public:
CDaoDatabase* m_pDB;
CString m_strDBName;
CString m_strModulePath;

enum ERROR_CODE
{
ERROR_NULL_DB = -100,
ERROR_DB_NOT_OPEN = -101,
ERROR_DB_DATA_NOT_FOUNT = -102,
ERROR_DB_DUP_INDEX_FIDLE = -103,
ERROR_MEMORY_EXCEPTION = -1000
};

int InitDB(void);

int CheckDB(void);
bool CreateDB(CString strDBName);
bool CreateTable(CDaoDatabase* pDB);
};


////////////////////////////////////////////////////////////////////////////
// Source

#include "StdAfx.h"
#include "libdb.h"

CLibDB::CLibDB(void)
{
m_pDB = NULL;

// Get Module Path
m_strModulePath = _T("");

char sfilename[255];
GetModuleFileName(NULL, sfilename, sizeof(sfilename));

char Drive[255];
char Path[255];
char Filename[255];
char Ext[255];
_splitpath(sfilename, Drive, Path, Filename, Ext);

m_strModulePath.Format(_T("%s%s"), Drive, Path);

m_strDBName = m_strModulePath + _T("\MyMDB.mdb");
}

CLibDB::~CLibDB(void)
{
if(m_pDB)
{
if(m_pDB->IsOpen())
m_pDB->Close();
delete m_pDB;
}
}

LPCTSTR CLibDB::strBOOL(BOOL bFlag)
{
return bFlag ? _T("TRUE") : _T("FALSE");
}

CString CLibDB::strVARIANT(const COleVariant& var, char *pBuf /*= NULL*/)
{
CString strRet;
strRet = _T("UNKNOWN");

switch(var.vt){
case VT_EMPTY:
case VT_NULL:
strRet = _T("NULL");
break;
case VT_I2:
strRet.Format(_T("%hd"),V_I2(&var));
break;
case VT_I4:
strRet.Format(_T("%d"),V_I4(&var));
break;
case VT_R4:
strRet.Format(_T("%f"),(double)V_R4(&var));
break;
case VT_R8:
strRet.Format(_T("%f"),V_R8(&var));
break;
case VT_CY:
strRet = COleCurrency(var).Format();
break;
case VT_DATE:
strRet = COleDateTime(var).Format(_T("%m %d %y"));
break;
case VT_BSTR:
strRet = V_BSTRT(&var);
break;
case VT_DISPATCH:
strRet = _T("VT_DISPATCH");
break;
case VT_ERROR:
strRet = _T("VT_ERROR");
break;
case VT_BOOL:
return strBOOL(V_BOOL(&var));
case VT_VARIANT:
strRet = _T("VT_VARIANT");
break;
case VT_UNKNOWN:
strRet = _T("VT_UNKNOWN");
break;
case VT_I1:
strRet = _T("VT_I1");
break;
case VT_UI1:
strRet.Format(_T("0x%02hX"),(unsigned short)V_UI1(&var));
break;
case VT_UI2:
strRet = _T("VT_UI2");
break;
case VT_UI4:
strRet = _T("VT_UI4");
break;
case VT_I8:
strRet = _T("VT_I8");
break;
case VT_UI8:
strRet = _T("VT_UI8");
break;
case VT_INT:
strRet = _T("VT_INT");
break;
case VT_UINT:
strRet = _T("VT_UINT");
break;
case VT_VOID:
strRet = _T("VT_VOID");
break;
case VT_HRESULT:
strRet = _T("VT_HRESULT");
break;
case VT_PTR:
strRet = _T("VT_PTR");
break;
case VT_SAFEARRAY:
strRet = _T("VT_SAFEARRAY");
break;
case VT_CARRAY:
strRet = _T("VT_CARRAY");
break;
case VT_USERDEFINED:
strRet = _T("VT_USERDEFINED");
break;
case VT_LPSTR:
strRet = _T("VT_LPSTR");
break;
case VT_LPWSTR:
strRet = _T("VT_LPWSTR");
break;
case VT_FILETIME:
strRet = _T("VT_FILETIME");
break;
case VT_BLOB:
strRet = _T("VT_BLOB");
break;
case VT_STREAM:
strRet = _T("VT_STREAM");
break;
case VT_STORAGE:
strRet = _T("VT_STORAGE");
break;
case VT_STREAMED_OBJECT:
strRet = _T("VT_STREAMED_OBJECT");
break;
case VT_STORED_OBJECT:
strRet = _T("VT_STORED_OBJECT");
break;
case VT_BLOB_OBJECT:
strRet = _T("VT_BLOB_OBJECT");
break;
case VT_CF:
strRet = _T("VT_CF");
break;
case VT_CLSID:
strRet = _T("VT_CLSID");
break;
}
WORD vt = var.vt;
if(vt & VT_ARRAY){
#pragma warning(disable : 4244)
vt = vt & ~VT_ARRAY;
#pragma warning(default : 4244)
strRet = _T("Array of ");
}
if(vt & VT_BYREF){
#pragma warning(disable : 4244)
vt = vt & ~VT_BYREF;
#pragma warning(default : 4244)
strRet += _T("Pointer to ");
}
if(vt != var.vt){
switch(vt){
case VT_EMPTY:
strRet += _T("VT_EMPTY");
break;
case VT_NULL:
strRet += _T("VT_NULL");
break;
case VT_I2:
strRet += _T("VT_I2");
break;
case VT_I4:
strRet += _T("VT_I4");
break;
case VT_R4:
strRet += _T("VT_R4");
break;
case VT_R8:
strRet += _T("VT_R8");
break;
case VT_CY:
strRet += _T("VT_CY");
break;
case VT_DATE:
strRet += _T("VT_DATE");
break;
case VT_BSTR:
strRet += _T("VT_BSTR");
break;
case VT_DISPATCH:
strRet += _T("VT_DISPATCH");
break;
case VT_ERROR:
strRet += _T("VT_ERROR");
break;
case VT_BOOL:
strRet += _T("VT_BOOL");
break;
case VT_VARIANT:
strRet += _T("VT_VARIANT");
break;
case VT_UNKNOWN:
strRet += _T("VT_UNKNOWN");
break;
case VT_I1:
strRet += _T("VT_I1");
break;
case VT_UI1:
strRet += _T("VT_UI1");
break;
case VT_UI2:
strRet += _T("VT_UI2");
break;
case VT_UI4:
strRet += _T("VT_UI4");
break;
case VT_I8:
strRet += _T("VT_I8");
break;
case VT_UI8:
strRet += _T("VT_UI8");
break;
case VT_INT:
strRet += _T("VT_INT");
break;
case VT_UINT:
strRet += _T("VT_UINT");
break;
case VT_VOID:
strRet += _T("VT_VOID");
break;
case VT_HRESULT:
strRet += _T("VT_HRESULT");
break;
case VT_PTR:
strRet += _T("VT_PTR");
break;
case VT_SAFEARRAY:
strRet += _T("VT_SAFEARRAY");
break;
case VT_CARRAY:
strRet += _T("VT_CARRAY");
break;
case VT_USERDEFINED:
strRet += _T("VT_USERDEFINED");
break;
case VT_LPSTR:
strRet += _T("VT_LPSTR");
break;
case VT_LPWSTR:
strRet += _T("VT_LPWSTR");
break;
case VT_FILETIME:
strRet += _T("VT_FILETIME");
break;
case VT_BLOB:
strRet += _T("VT_BLOB");
break;
case VT_STREAM:
strRet += _T("VT_STREAM");
break;
case VT_STORAGE:
strRet += _T("VT_STORAGE");
break;
case VT_STREAMED_OBJECT:
strRet += _T("VT_STREAMED_OBJECT");
break;
case VT_STORED_OBJECT:
strRet += _T("VT_STORED_OBJECT");
break;
case VT_BLOB_OBJECT:
strRet += _T("VT_BLOB_OBJECT");
break;
case VT_CF:
strRet += _T("VT_CF");
break;
case VT_CLSID:
strRet += _T("VT_CLSID");
break;
}
}

if (pBuf != NULL)
{
int nChar = strRet.GetLength();
#ifdef _UNICODE
WideCharToMultiByte( CP_ACP, 0, strRet, -1,
pBuf, nChar, NULL, NULL );
#else
strcpy(pBuf, (LPCSTR)(LPCTSTR)strRet);
#endif
pBuf[nChar] = '\0';
}

return strRet;
}

void CLibDB::DisplayDaoException(CDaoException* e)
{
CString strMsg;
if (e->m_pErrorInfo != NULL)
{
strMsg.Format(
_T("%s (%d)"),
(LPCTSTR)e->m_pErrorInfo->m_strDescription,
e->m_pErrorInfo->m_lErrorCode);
AfxMessageBox(strMsg);
}
else
{
strMsg.Format(
_T("ERROR:CDaoException\n\n")
_T("SCODE_CODE =%d\n")
_T("SCODE_FACILITY =%d\n")
_T("SCODE_SEVERITY =%d\n")
_T("ResultFromScode =%d\n"),
SCODE_CODE (e->m_scode),
SCODE_FACILITY (e->m_scode),
SCODE_SEVERITY (e->m_scode),
ResultFromScode (e->m_scode));
AfxMessageBox(strMsg);
}
}

BOOL CLibDB::IsExistentTable(CDaoDatabase *pDatabase, CString strTableName)
{
CDaoDatabase *pDB = NULL;
BOOL bDuplicateTableName = TRUE;

if (pDatabase == NULL)
pDB = m_pDB;
else
pDB = pDatabase;

if (pDB == NULL)
return FALSE;

CDaoTableDefInfo tableInfo; // only needed for the call

TRY
{
pDatabase->GetTableDefInfo(strTableName, tableInfo);
}
CATCH (CDaoException, e)
{
if (e->m_pErrorInfo->m_lErrorCode == 3265)
bDuplicateTableName = FALSE;
}
AND_CATCH (CMemoryException, e)
{
// do nothing
;
}
END_CATCH

return bDuplicateTableName;
}

int CLibDB::InitDB()
{
if (m_pDB)
{
if (m_pDB->IsOpen())
m_pDB->Close();

delete m_pDB;
m_pDB = NULL;
}

m_pDB = new CDaoDatabase;

CheckDB();

return 0;
}

int CLibDB::CheckDB(void)
{
CFileStatus fileStatus;

if (CFile::GetStatus( m_strDBName, fileStatus ))
{
CDaoDatabase* pDB = new CDaoDatabase;
CString strQuery;

pDB->Open(m_strDBName);

if (pDB->IsOpen())
{
if (IsExistentTable(pDB, "MYGROUP") == FALSE ||
IsExistentTable(pDB, "MEMBER") == FALSE)
{
AfxMessageBox("Database damaged. Recreate database");
CreateTable(pDB);
}
}

if(pDB)
{
if(pDB->IsOpen())
pDB->Close();
delete pDB;
}
// Find DB File
}
else
{
// DB File Not Found
AfxMessageBox("DB Not Found!!\n\nCreate database.");

CreateDB(m_strDBName);
}


return 0;
}

bool CLibDB::CreateDB(CString strDBName)
{
CDaoDatabase* pDB = new CDaoDatabase;

pDB->Create(strDBName);

if(!pDB)
{
TRACE("Fail to Create Database");
return false;
}
else
{
CreateTable(pDB);

if(pDB->IsOpen())
pDB->Close();
delete pDB;
}

return true;
}

bool CLibDB::CreateTable(CDaoDatabase* pDB)
{
if (!pDB)
return false;

if (!pDB->IsOpen())
return false;

CString strQuery;

TRY {
// Create Comopnent Table
strQuery.Format(
"CREATE TABLE MYGROUP ("
" GROUPID INTEGER PRIMARY KEY"
", ALIAS VARCHAR(50)"
", MEMBERS INTEGER"
")"
);

pDB->Execute(strQuery);
}
CATCH (CDaoException, e)
{
DisplayDaoException(e);
}
END_CATCH


TRY {
// Create Address
CDaoTableDef Table(pDB);
CDaoFieldInfo Field;

Table.Create("MEMBER");

Field.m_strName = "NAME";
Field.m_nType = dbText;
Field.m_lSize = 50;
Field.m_lAttributes = dbVariableField;
Field.m_bRequired = TRUE;
Field.m_bAllowZeroLength = FALSE;
Field.m_lCollatingOrder = dbSortGeneral;
Table.CreateField(Field);

Table.CreateField("GROUPID", dbInteger, 4);
Table.CreateField("NAME", dbText, 80);
Table.CreateField("AGE", dbInteger, 4);
Table.CreateField("HEIGHT", dbSingle, 4);
Table.CreateField("WEIGHT", dbSingle, 4);

Field.m_nType = dbBoolean;
Field.m_lSize = 1;
Field.m_lAttributes = dbFixedField | dbUpdatableField;
Field.m_bRequired = TRUE;
Field.m_bAllowZeroLength = FALSE;
Field.m_strDefaultValue = "1";

Field.m_strName = "Gender";
Table.CreateField(Field);

Field.m_strName = "IsAdult";
Table.CreateField(Field);

Table.Append();
}
CATCH (CDaoException, e)
{
DisplayDaoException(e);
}
END_CATCH

return true;
}

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

MFC MDI 에서 초기 자식창 생성 막기


CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);

// Don't display a new MDI child window during startup
if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileNew)
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;

if (!ProcessShellCommand(cmdInfo))
return FALSE;

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

Dialog 위에 ScrollView 올리기


////////////////////////////////////////////////////////////////////////
//On View

//header
public:
virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName
, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd
, UINT nID, CCreateContext* pContext = NULL);


//source
BOOL CSampleView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName
, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd
, UINT nID, CCreateContext* pContext)
{
return CWnd::Create(lpszClassName, lpszWindowName,
dwStyle, rect, pParentWnd, nID, pContext);
}

int CSampleView::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest
, UINT message)
{
return MA_ACTIVATE;
//return CScrollView::OnMouseActivate(pDesktopWnd, nHitTest, message);
}

////////////////////////////////////////////////////////////////////////
//On Dialog

CRect rt;
GetClientRect(rt);
m_pScrollView = new CSampleView();
m_pScrollView->Create (NULL, NULL, WS_VISIBLE | WS_CHILD,
rt, this, 10000, NULL);

CSize sizeTotal;
sizeTotal.cx = sizeTotal.cy = 100;
m_pScrollView->SetScrollSizes(MM_TEXT, sizeTotal);

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

2008/10/08

비어있지 않은 레지스트리 키 지우기 - SHDeleteKey

#include <Shlwapi.h>

DWORD Result = SHDeleteKey(HKEY_CURRENT_USER, "Software\Microsoft\...");

switch(Result)
{
case ERROR_SUCCESS:
// Registry Deleted
break;

case ERROR_FILE_NOT_FOUND:
// Registry key not found
break;

default:
break;
}

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

Folder 선택하기 SHBrowseForFolder

    char m_szWorkPath[MAX_PATH];

LPITEMIDLIST pidlBrowse;
BROWSEINFO info;

info.hwndOwner = this->GetSafeHwnd(); // 부모 윈도우의 핸들
info.pidlRoot = NULL;
info.pszDisplayName = m_szWorkPath;
info.lpszTitle = "Select Directory";
info.ulFlags = BIF_RETURNONLYFSDIRS;
info.lpfn = NULL;
info.lParam = 0; //m_szWorkPath;

pidlBrowse = SHBrowseForFolder(&info); // 다이얼로그를 띄운다.
if(pidlBrowse != NULL)
{
SHGetPathFromIDList(pidlBrowse, m_szWorkPath); // 패스를 얻어온다.
}

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

2008/10/07

굿모닝팝스 MP3 다운로더 v7.0.0.36

사용자 삽입 이미지


이번 버전에 바뀐 점
      - 파일 열기 기능 추가
      - 다운로드 받은 후 재생기능 추가


다운로드 속도가 너무 느려 실시간 듣기는 의미가 없어 보인다. 다운로드 속도를 개선하지 않는 한 다음 업그레이드는 없을 듯하다.

2008/10/04

굿모닝팝스 MP3 다운로더 v7.0.0.32

사용자 삽입 이미지

단팥 사이트가 부분 유료화가 되어버리면서 다운 받기도 어려워졌고 다운로드 속도 또한 많이 느려졌다. 예전에 굿모닝 팝스 MP3 재생기라는 프로그램이름을 달고 만들었는데 다운로드가 너무 느려지는 바람에 실시간 재생은 큰 의미를 잃어 버리게 되었다. 다운로드 또한 많이 느려진 탓에 이 프로그램을 통한 다운로드도 크게 의미를 잃었다.

프로그램을 만들은 본인도 많이 애용하고 있는 프로그램이였는데 이제는 MP3 URL 을 복사하는 용도로 밖에 사용하지 않는다. URL을 복사해서 FlashGet 같은 다운로드 전용 프로그램을 통해 다운 받는 것이 보다 빠르게 다운 받을 수 있기 때문이다.
사용자 삽입 이미지


이번 버전에서는 최종으로 다운로드 받은 경로를 기억하는 기능과 다운로드 창을 조금 개선하였다.

다음 버전은 다운로드 완료 후 다운로드 받은 파일을 재생하는 기능을 넣을 예정이다. (일정은 미정)

Delphi Distiller v1.51 released

델파이툴(5/6/7/2006/2007/2009)의 여러가지 트윅을 설정 할 수 있는 프로그램이다.

Delphi Distiller v1.51 지원 기능

- Choose what packages and experts are loaded by Delphi 5/6/7/2006/2007/2009.

- File associations manager for Delphi 5/6/7/2006/2007/2009.

- Delphi 5 tweaks:
  - Don't create .~bpl files.
  - Don't create .cfg files.
  - Use Tahoma font by default.
  - Don't show splash screen.
  - Customize editor colors.
  - Trial to Retail conversion.

- Delphi 6 tweaks:
  - Don't create .~bpl files.
  - Don't create .ddp files.
  - Don't create .cfg files.
  - Use Tahoma font by default.
  - Don't show splash screen.

- Delphi 7 tweaks:
  - Don't create .~bpl files.
  - Don't create .ddp files.
  - Don't create .cfg files.
  - Use Tahoma font by default.
  - Don't show splash screen.

- Delphi 2006 tweaks:
  - Don't create .~bpl files.
  - Don't create .local files.
  - Don't create .cfg files.
  - Remove toolbar gradients.
  - Fix TabStop bug in TFrame's.
  - Don't show splash screen.

- Delphi 2007 tweaks:
  - Don't create .~bpl files.
  - Don't create .local files.
  - Don't check for updates when the IDE starts.
  - Avoid loading of additional .NET crap by delphicoreide100.bpl.
  - Remove toolbar gradients.
  - Don't show splash screen.

- Delphi 2009 tweaks:
  - Don't create .~bpl files.
  - Don't create .local files.
  - Don't check for updates when the IDE starts.
  - Avoid loading of additional .NET crap by delphicoreide120.bpl.
  - Don't show splash screen.


버전 히스토리 보기



Tip. Ctrl + Alt + L 을 누르면 멋진 걸 볼 수 있다.

홈페이지
Original Post :
http://neodreamer-dev.tistory.com/177

2008/10/01

드디어 GExperts 1.33 Beta for Delphi 2009 가 공개되었다.

사용자 삽입 이미지


Delphi 와 C++ Builder 의 IDE Plugin 인 Gexperts 가 드디어 RAD Studio 2009 용 버전을 공개하였다. 비록 아직은 Beta버전 이지만 요긴하게 사용할 수 있을 것 같다.

Gexperts Official Website
Gexperts README.txt
Gexperts Download
Original Post :
http://neodreamer-dev.tistory.com/176