SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

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

C#でSQLiteを使うには


  • X ポスト
  • このエントリーをはてなブックマークに追加

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

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめに

 前回のアーティクル「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

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
アフター・ケアとDLLのつくりかた 2

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

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

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1382 2008/08/19 19:22

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング