Listviewのテキストコールバックとオーナーデータの違い

テキストコールバック

InsertItemでテキストにLPSTR_TEXTCALLBACKを指定する。LVN_GETDISPINFOが飛んでくるのでここでテキストをセットする。データは構造体などで持ってListViewのLParamに設定しておくのがいいと思われる。テキストと同様にアイコンもI_IMAGECALLBACKを指定することにより同じようにできる。

オーナーデータ

ListViewの作成時にLVS_OWNERDATAを指定する。InsertItemは使わず、データは並びも含めてアプリが持つ。アプリがセットするのはSetItemCountExによるアイテムの個数だけで、これをやるとLVN_GETDISPINFOが飛んでくるのでここで表示データをセットする。

どちらもLVN_GETDISPINFOが来たときはポインタだけ設定すればいいはずでListViewはコピーを持たない。pszTextはコンストでないがこれは取得用もかねているためでコンストキャストしていいはず。

 

 

MSYSとMingWでwin32のDLLをつくる

MingWとMSYSはインストールされているものとする。

以下のファイルwinhello.cを作成する。

MSYSシェルからコンパイルする。

成功するとwinhello.dllができる。

これをrundll32.exeを使って実行してみる。

できた。

VC6でデバッグビルドでは動くのにリリースビルドだと動かない場合

リリースビルドでもデバッグ情報をある程度付け足してビルドすることができるのでその方法。

1、メニューの「ビルド」「構成」からリリースビルドの構成を元に新しい構成を作成する。

2、プロジェクトの設定の、「C/C++」でデバッグ情報を「プログラムデータベースを使用」にする。「リンク」で、「デバッグ情報を生成する」をチェックする。

3、実行してエラーが出てくれれば、行番号などのある程度の情報はわかる。

上の方法でエラーが出てくれないとき。

1、リリースビルドのプロジェクトの設定の「リンク」で「MAPファイル生成」をチェックし、ビルドすると拡張子MAPのファイルができる。このファイルは関数のアドレス情報がわかる。

2、実行してエラーを再現して、エラーの起きたアドレスを調べる。以下の場合ならアドレスは0x401106になる。

err

3、MAPファイルからこのアドレスがどの関数かを調べる。左の数値ではなく右のほうの400000あたりから始まる数値。

4、頑張ればコールスタックも調べられる。

Visual C++でSQLiteを使う

SQLiteはデータベースです。データベースというと一般的にはサーバですが、SQLiteはただのライブラリでアプリケーションに組み込んで使えます。SQLiteのソースコードはamalgamationされている状態で提供されています。amalgamationとは、全部のソースコードを1つのファイルにまとめることのようです。amalgamationで提供されるファイルは、Cのソースファイルが1つとヘッダ2つだけしかありませんので簡単に既存のプロジェクトに組み入れることができます。

ここではVisual C++ ver 6でダイアログベースのアプリケーションを作成して、SQLiteを組み込んでみます。

DBを作成する

最初にデータベースを作成します。SQLiteのダウンロードページからPrecompiled Binaries For Windowsの中のコマンドラインツールをダウンロードして解凍します。ここではhsqlite-3_6_6_2.zipをダウンロードしました。sqlite3.exeというファイルが解凍されるので、これを以下のようにコマンドラインから起動して、データベースを作成します。

これでtestdb.dbというファイルができます。
 

AppWizardでダイアログベースアプリを作成

VC6でプロジェクトを作成します。
 

SQLiteのamalgamationソースコードを組み込む

SQLiteのダウンロードページからamalgamationのソースコードをダウンロード、ここではsqlite-amalgamation-3_6_6_2.zipをダウンロードしました。

ダウンロードしたファイルを解凍して中の3つのファイル,sqlite3.c,sqlite3.h,sqlite3ext.hをプロジェクトフォルダにコピーしてから、VC6で[プロジェクト][プロジェクトへ追加][ファイル]を選択して、これらのファイルを追加します。

sqlite3.cがプリコンパイルを使用しないようにプロジェクトの設定を変更します。

ビルドして、エラーにならないか確認します。ウォーニングはいっぱい出ます。

コーディングする

ダイアログにボタンを追加して、ハンドラを追加してコードを書きます。最初にヘッダファイルをインクルードします。

つぎにハンドラにコードを書きます。

sqlite3_open()などに渡す文字列はUTF8で渡さなければなりませんので日本語が含まれる場合は、注意する必要があります。UTF16で渡すことができるバージョンの関数もあります。
 

実行

上のプログラムを実行すると、以下のように表示されます。

アプリケーションの設定をどうやって保存するか? ini vs レジストリ vs xml

1, その保存場所について

いままでは設定の保存はGetPrivatePrifile* APIを使ってiniファイルに保存していればよかったんですが、Vistaの登場でそういうわけにはいかなくなってしまいました。Vistaでは”Program files”下に置かれたアプリがexeのあるフォルダにファイルを作ることも書き込むことも許してくれないみたいです。

iniファイルの利点は、フォルダを削除すればアプリケーションのすべてのファイルを一括削除できることにあると思います。痕跡は残りません。もちろんOSがいろいろ残すでしょうから痕跡が全く残らないわけではありませんが。また設定ファイルのせいでアプリの挙動がおかしくなったときでも、iniファイルを削除してしまえば初期値に戻るので復旧が簡単です。

復旧といえばインストーラでインストールもアンインストールもできなくなって困った経験がある人も多いんじゃないでしょうか?

さて、レジストリに書き込むとユーザーごとに別々の場所に書くことになるので、アンインストーラーが本当に全員分の設定を削除してくれているのかはわかりません。もちろんこれはユーザーごとの”Documents and Settings”配下にデータを置いた場合も同じです。つまりアプリを色々使えば使うほどゴミファイルがどんどんたまっていってしまうのです。またアプリの設定場所が固定されているとウイルスも作りやすくなってしまいます。

よってアプリの設定情報は、そのフォルダの配下に置いた方がいいんじゃないでしょうか。ユーザーごとに分けたい場合は”user”フォルダを作成し、その配下におけばいいですし。

2, 保存のフォーマット

話は変わってxmlですが、なんか呼び方がserialilzeとかdeserializeとかになってますね。でもこれって退化じゃないでしょうか?いままではそういうことを意識しなくてもよかったのに連続化という下位概念を持ち出してくるわけですから。

そしてこれは言葉の問題だけじゃなくて本当に意識しなければいけないのではないでしょうか?iniファイルやレジストリの場合には、保存の際、それが壊れてしまうということを意識しなくてもよかったと思いますが、xmlで一気に書くとなると、もし書き始めたときにPCが固まってしまったら全部壊れるんじゃないかとか、また、ユーザーがエディタでそれをいじって読み込み不能になって、終了時デフォルト値のまま全部保存しちゃって結局全部消えちゃうとか、あるいはクラスの構成が変わったときの互換性は大丈夫かとか、考えなくてはいけないことが一気に多くなるような気がします。もちろんちゃんと調べたわけではないので嘘いってるかもしれませんが。

逆にxmlで有利な点はUTF-8で書けることだとおもいます。そしてそれはWindows98系でも同じなんでしょう(多分)。iniファイルだとそれが難しいです。W系のAPIを使ってしまうと98系で動かなくなりますし、A系だと中国語や韓国語が保存できません。あえてやるとすればGetPrivateProfileStructでバイナリ保存でしょうが、これだとユーザーが編集できなくなってしまいます。