Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

C++/CLIによるCライブラリの.NET化

C#でSQLiteを使うには

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2007/06/19 14:00

Managed C++ の後継として Visdual Studio 2005 に搭載されたC++/CLIはnativeなC/C++ライブラリをC#/VBから利用するための仲介役の実現手段を提供します。Cによる小型軽量SQLライブラリ:SQLiteをC++/CLIでくるみ、C#から呼び出すまでの手順を解説します。

目次

はじめに

 前回のアーティクル「SQLiteで組み込みDB体験(2007年版)」は、

SQLiteはお手軽軽量なDBとしてさまざまなアプリケーションに使えるものと思います。このお手軽さを享受できるのがC/C++だけではもったいない。C++/CLIで薄いラッパーを被せれば、C#やVB.NETから使えるようにできるはずですが、そのお話はまたいずれ。

 ……という、なんとも思わせぶりな「まとめ」で締めくくってました、このまま放っておくわけにもいきませんよね。

 そんなわけで続編、C++/CLIでSQLiteに薄いラッパーを被せ、C#から呼び出す試みです。基本的にどんなC/C++コードでもC++/CLIでラッパーを被せることで.NET化できるはず。ネタに用いたSQLiteはC++/CLIによるラッパーの1つのサンプルと考えてください。

対象読者

  • C/C++で書かれたコードをなんとかC#/VBでも使いたい方

必要環境

  • Visual C++ 2005 Express Edition もしくは Visual Studio 2005
  • SQLite version 3.3.17

アフター・ケアとDLLのつくりかた 1

 さて、いきなりお詫びをしなくてはなりません。前回公開直前にSQLiteのバージョンが3.3.16から3.3.17に上がってました。あまりのことに修正が間に合わず旧版のままで公開することになりました。

 お詫びも兼ねて、より簡単に日本語サポートのための関数を追加する手順、およびDLLの作成手順を紹介しておきます。

  1. SQLite home pagedownloadから「sqlite-source-3_3_17.zip」と「sqlitedll-3_3_17.zip」をダウンロードします。
  2.  
  3. 次にVC8EEのIDEを起動し、ソリューション「SQLite3」に、スタティック・ライブラリ・プロジェクト「sqlite3」を作成します。
  4.  
  5. ダウンロードしたsqlite-source-3_3_17.zipとsqlitedll-3_3_17.zipを展開し、「sqlite3.h」「sqlite3.c」「sqlite3.def」を[プロジェクト]-[ディレクトリ]-[...\SQLite3\sqlite3]に配置します。
  6. さらに以下の3つ、「legacy16.h」「legacy16.c」「legacy16.bat」も[...\SQLite3\sqlite3]に置いてください。
legacy16.h
#ifndef LEGACY16_H__
#define LEGACY16_H__

#ifdef __cplusplus
extern "C"
#endif

typedef int (*sqlite3_callback16)(void*,int,__wchar_t**, __wchar_t**);

int sqlite3_exec16(
  sqlite3 *db,            /* The database on which the SQL executes */
  const __wchar_t *zSql,        /* The SQL to be executed */
  sqlite3_callback16 xCallback, /* Invoke this callback routine */
  void *pArg,                   /* First argument to xCallback() */
  __wchar_t **pzErrMsg          /* Write error messages here */
);

#ifdef __cplusplus
}
#endif

#endif
legacy16.c
typedef int (*sqlite3_callback16)(void*,int,__wchar_t**, __wchar_t**);

int sqlite3_exec16(
  sqlite3 *db,            /* The database on which the SQL executes */
  const __wchar_t *zSql,        /* The SQL to be executed */
  sqlite3_callback16 xCallback, /* Invoke this callback routine */
  void *pArg,                   /* First argument to xCallback() */
  __wchar_t **pzErrMsg          /* Write error messages here */
){
  int rc = SQLITE_OK;
  const __wchar_t *zLeftover;
  sqlite3_stmt *pStmt = 0;
  __wchar_t **azCols = 0;

  int nRetry = 0;
  int nChange = 0;
  int nCallback;

  if( zSql==0 ) return SQLITE_OK;
  while( (rc==SQLITE_OK || 
         (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
    int nCol;
    __wchar_t **azVals = 0;

    pStmt = 0;
    rc = sqlite3_prepare16(db, zSql, -1, &pStmt, &zLeftover);
    assert( rc==SQLITE_OK || pStmt==0 );
    if( rc!=SQLITE_OK ){
      continue;
    }
    if( !pStmt ){
      /* this happens for a comment or white-space */
      zSql = zLeftover;
      continue;
    }

    db->nChange += nChange;
    nCallback = 0;

    nCol = sqlite3_column_count(pStmt);
    azCols = sqliteMalloc(2*nCol*sizeof(const __wchar_t *) + 1);
    if( azCols==0 ){
      goto exec_out;
    }

    while( 1 ){
      int i;
      rc = sqlite3_step(pStmt);

      /* Invoke the callback function if required */
      if( xCallback && (SQLITE_ROW==rc ||
          (SQLITE_DONE==rc 
           && !nCallback 
           && db->flags&SQLITE_NullCallback)) ){
        if( 0==nCallback ){
          for(i=0; i<nCol; i++){
            azCols[i] = (__wchar_t*)sqlite3_column_name16(pStmt, i);
          }
          nCallback++;
        }
        if( rc==SQLITE_ROW ){
          azVals = &azCols[nCol];
          for(i=0; i<nCol; i++){
            azVals[i] = (__wchar_t*)sqlite3_column_text16(pStmt, i);
          }
        }
        if( xCallback(pArg, nCol, azVals, azCols) ){
          rc = SQLITE_ABORT;
          goto exec_out;
        }
      }

      if( rc!=SQLITE_ROW ){
        rc = sqlite3_finalize(pStmt);
        pStmt = 0;
        if( db->pVdbe==0 ){
          nChange = db->nChange;
        }
        if( rc!=SQLITE_SCHEMA ){
          nRetry = 0;
          zSql = zLeftover;
          while( iswspace((wint_t)zSql[0]) ) zSql++;
        }
        break;
      }
    }

    sqliteFree(azCols);
    azCols = 0;
  }

exec_out:
  if( pStmt ) sqlite3_finalize(pStmt);
  if( azCols ) sqliteFree(azCols);

  rc = sqlite3ApiExit(0, rc);
  if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
    *pzErrMsg = malloc( 
                  (wcslen((const __wchar_t*)sqlite3_errmsg16(db)) +1)
                   *sizeof(__wchar_t));
    if( *pzErrMsg ){
      wcscpy(*pzErrMsg, sqlite3_errmsg16(db));
    }
  }else if( pzErrMsg ){
    *pzErrMsg = 0;
  }

  return rc;
}
legacy16.bat
md original
move sqlite3.h original\sqlite3.h
copy original\sqlite3.h+legacy16.h sqlite3.h
move sqlite3.c original\sqlite3.c
copy original\sqlite3.c+legacy16.c sqlite3.c
copy sqlite3.def original\sqlite3.def
echo sqlite3_exec16 >> sqlite3.def

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • επιστημη(エピステーメー)

    C++に首まで浸かったプログラマ。 Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"り わんくま同盟でたまにセッションスピーカやったり 中国茶淹れてにわか茶人を気取ってたり、 あと Facebook とか。 著書: - STL標準...

All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5