#norelated #contents * Today プラグインサンプルプログラム [#l3bd18a2] ** 手順 [#ca9d4d47] 基本的には[[Windows Mobileサンプルプログラム]]とプロジェクト作成方法は変わりませんが、アプリケーションの種類をDLLにしておきましょう。~ シンボルは後で、defファイルを使ってエクスポートするので、チェックはいらないです。~ #ref(Application.png,left,nowrap,アプリケーションの設定) これで、DllMainのみのソースが作成されますので、ここに必要なものを追加していきましょう。~ ** シェルからコールされる関数のエクスポート [#cf76846c] Todayプラグインは、シェルからロードされる時に呼び出される関数「InitializeCustomItem」と、設定画面を作る場合は、その設定ダイアログ用のプロシージャ「CustomItemOptionsDlgProc」を、定義して外部から参照できるようにする必要があります。~ まだ設定画面を作るかどうかはわかりませんが、一応、両方定義しておきましょう。~ まずはソース(DllMainの下にでも)に、以下を追加します。~ HWND APIENTRY InitializeCustomItem( TODAYLISTITEM *ptli, HWND hwndParent ) { return NULL; } BOOL APIENTRY CustomItemOptionsDlgProc( HWND hDlg, UINT message, UINT wParam, LONG lParam ) { return FALSE; } TODAYLISTITEMの定義が、デフォルトでは参照できないので、以下のincludeも追加しておきましょう。~ プリコンパイルヘッダ(stdafx.h)の一番下のTODO以下でいいと思います。~ // TODO: プログラムに必要な追加ヘッダーをここで参照してください。 #include <todaycmn.h> InitializeCustomItemは、これから、today画面に表示するWindowを作成して、そのWindowハンドルを返すことになります。~ CustomItemOptionsDlgProcは、設定ダイアログを作った場合、そのダイアログのメッセージ処理を書きます。~ ダイアログプロシージャは、メッセージを処理した場合にTRUEを返すので、とりあえず今はFALSEで。~ 次に、追加した関数を、DLLの外から見えるようにしてやる必要があります。~ しかも、これらの関数は、外からコールする際の関数の番号(序数)を240番と241番という値に固定してやらなければなりません。~ このために、defファイルを使用したエクスポートの設定をしてやります。~ まずは、ソリューションエクスプローラの追加したい箇所で右クリックして、追加→新しい項目を選びます。~ ソースにでも追加しておきますかね。~ #ref(adddef.png,left,nowrap,新しい項目) で、コードのモジュール定義ファイルを選んで、適当に名前を入力します。~ #ref(adddef2.png,left,nowrap,新しい項目の追加) 出来たdefファイルには、ライブラリ名だけが記述されていますので、EXPORTS指定をして、先程の2関数を序数指定で追加します。~ LIBRARY "todaytest" EXPORTS InitializeCustomItem @240 CustomItemOptionsDlgProc @241 上記手順で作れば、自動的にプロジェクトのプロパティに、モジュール定義ファイルとして設定されていると思いますので、確認してみてください。~ 手動でファイルを追加した場合は、モジュール定義ファイルの項目に、追加したファイルを設定してやる必要があります。~ #ref(moduledef.png,left,nowrap,モジュール定義ファイル) この状態でビルドしてやれば、dllとexp(エクスポートファイル)と、インポートライブラリ(lib)ファイルが生成されるはずです。~ とはいえ、シェルはダイナミックにdllをロードして、序数指定で関数をコールするので、このインポートライブラリを使う人はいませんが。~ ** ウィンドウクラス登録 [#ke025966] InitializeCustomItemで、表示するWindowを作成するために、まずはウィンドウクラスを登録する必要があります。~ 登録は普通のWin32プログラムとほとんど変わらないのですが、DLLでの登録なので、シェルがDLLを呼び出してる間だけ、ウィンドウクラスが有効である必要があります。~ InitializeCustomItem内でウィンドウクラスの登録を行なおうとすると、初回はいいのですが、何らかのタイミングで一旦todayプラグインのWindowをつくり直す契機があった場合、シェルはInitializeCustomItemで作ったWindowを一旦Destroyして、再度InitializeCustomItemをコールし、ウィンドウの再作成をすることがあるという作りらしいので、2回目以降にコールされたとき、既にウィンドウクラスが登録されている状態になってしまいます。~ これを防ぐために、DllMainで、プロセスにアタッチされた時に、ウィンドウクラスの登録やリソースをロードし、プロセスからデタッチされた時に、これらを解放するという仕組みが、正攻法のようです。~ ウィンドウクラスに登録する名前とかは、定数でもいいんですけど、リソースのストリングテーブルとかに持ってたほうがいいかもしれませんね。~ どうせ後で、他のことにもリソースは使いそうなので、リソースファイルを追加しておきますか。~ というわけで、先ほどと同じように、リソースに追加します。~ #ref(addres.png,left,nowrap,新しい項目) で、リソースのリソースファイルを選んで、適当に名前を入力します。~ #ref(addres2.png,left,nowrap,新しい項目の追加) リソースを追加すると、リソースのIDが記述されるresource.hがプロジェクトに追加されます。~ 使用するソースでは、こいつをincludeしてやる必要がありますので、DllMainの前の、他のincludeの後に追加しておきます。~ #include "resource.h" ちなみに、DllMainの前にincludeされているwindows.hとcommctrl.hですが、この記述はstdafx.hの方に移してしまっていいと思います。~ というか、windows.hは既にstdafx.h内に記述されているので、消してしまってもいいです。~ 基本的に変更されることがないヘッダファイルは、プリコンパイルヘッダ(stdafx.h)中に記述して、そうでないヘッダファイルは、実際に使用するファイルがincludeするようにするといいでしょう。~ 次に、リソースファイルを作ったので、ここにストリングテーブルを追加します。~ 右クリックでリソースの追加を選んで……。~ #ref(addstrtbl.png,left,nowrap,リソースの追加) String Tableを選択して、新規作成。~ #ref(addstrtbl2.png,left,nowrap,リソースの追加) 作成できたら、ウィンドウクラス名を登録するIDと文字列を入力します。~ #ref(addstrtbl3.png,left,nowrap,リソースの追加) ストリングテーブルの他に、ウィンドウクラスには、そのウィンドウクラスを指定して作成したWindowのメッセージを処理する、ウィンドウプロシージャが必要です。~ とりあえず、何もしない(デフォルトの処理のみを行う)ウィンドウプロシージャも作っておきましょう。~ LRESULT CALLBACK WndProc( HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam ) { return ::DefWindowProc( hwnd, uiMsg, wParam, lParam ); } これで、下準備は出来ました。~ 適当なクラスでも作って、インスタンスハンドルを保持したり、ストリングテーブルから文字列を読み込む処理のラッパー等の処理を作成することにします。~ というわけで、出来たクラスと使用側のDllMainがこんな感じでしょうか。~ まだ動かして試すところまでいっていないので、ちゃんと動くかどうかわかりませんが……。~ #ref(ウィンドウクラスソース.zip,left,nowrap,ウィンドウクラスソース) ** ウィンドウ作成 [#m36b94a0]