Imo Soft  | TOP | Imo Soft | ドン!3 | 大学関係 | 掲示板 | リンク |
日曜プログラマのソフト置き場 >> Imo Soft >> VB-Delphi(目次) >> VB-Delphi-第一回
03/09/23更新

Visual BasicプログラマのためのDelphi研究室


第一回 Visual Basicから呼び出せるDLLを作る

何をやるかというと...

 何か重い処理をDelphiで書いてやれば、我が家での測定結果を信じるなら、2倍のパフォーマンス向上が見込める!ならば、DelphiでDLLをつくろう!っていう企画です。こういうのって、VC++なんかで本とかでてますけど、Delphiではどうなんでしょう?まあ、VC++でやるのに比べてあまりに簡単すぎてかなりあっけなく終わってしまうんですが。
 で、Delphiで書いたDLLが行う処理は、『コイン投げを1000万回やったときの表のでる確率を統計的に求める!』です。返す値は約0.5に決まってんだろ、なんてことを言われてしまいそうですが、あくまで、例題なので。


プロジェクトの作成

[プロジェクトの作成の説明画像]
 まず、Delphiを起動したら、自動的にふつうのプロジェクトが開きますので、『ファイル』→『すべて閉じる』で閉じて下さい。つぎに、『ファイル』→『新規作成』→『その他』を選択します。(※クリックで画像を拡大、以下同じ)
[新規作成のダイアログの画像]
 『新規作成』のダイアログが開くので、『新規作成』タブの中の『DLL ウィザード』を選択して『OK』をクリックします。
ついで、『ファイル』『名前を付けて保存』から、プロジェクトを保存します。
今回は、『tossing_coin』というフォルダを作成し、プロジェクト名は『tossing_coin_dll』、ユニット名は『tossing_coin_unit』としました。
これで、プロジェクトの作成は完了です。後はカリカリとObject Pascalでコードを書けばOKです。
※今回は、新たなユニットを使用していないので関係ないですが、Delphiでは、プロジェクトに同名のソースファイルを複数保持することができません。たとえ、拡張子が違っていてもです。ユニットとはVBの標準モジュールの様にコードが保存されているファイルのことです。


コーディング

 まず、乱数を発生する方法を考えます。Delphiには『Random』という関数があります。この関数は、Integer型の引数『Range』を取ります。『Range』を省略すると、VBのRnd()関数と同じで、0≦Random<1の乱数を返します。『Range』を指定することで、 0≦Random<Rangeの乱数を返させることができます。
 今回の目的は、コイン投げシミュレーションですから、『Range』に『2』を渡して小数点以下を切り捨てることにします。小数点以下を切り捨てるには、整数型を返す『Trunc』関数を使います。VBの切り捨て機能を持つ関数と同名の『Int』という関数もありますが、これは返値が浮動小数点型なので今回は使用しません。
 あとは、コードを載せてから説明します…
(*↓追加↓*)』から『(*↑追加ここまで↑*)』を正確に入力して下さい。打ち込む場所は特に注意!!『begin end.』の前に入力すること。

コード(Delphi、tossing_coin_dll.dpr)

library tossing_coin_dll;
{ DLL でのメモリ管理について:
  もしこの DLL が引数や返り値として String 型を使う関数/手続きをエクスポー
  トする場合、以下の USES 節とこの DLL を使うプロジェクトソースの USES 節
  の両方に、最初に現れるユニットとして ShareMem を指定しなければなりません。
  (プロジェクトソースはメニューから[プロジェクト|ソース表示] を選ぶこと
  で表示されます)
  これは構造体やクラスに埋め込まれている場合も含め String 型を DLL とやり
  取りする場合に必ず必要となります。
  ShareMem は共用メモリマネージャである BORLNDMM.DLL とのインターフェース
  です。あなたの DLL と一緒に配布する必要があります。BORLNDMM.DLL を使うの
  を避けるには、PChar または ShortString 型を使って文字列のやり取りをおこ
  なってください。}

uses
  SysUtils,Classes;
{$R *.res}

(*↓追加↓*)
function TossingCoin(N: Integer): Double; stdcall;
var I: Integer; //変数の宣言
    Counter: Integer;
begin
    if N<=0 then //ゼロ以下の時はエラーなので-1を返す。
    begin
        result:=-1;
        exit;
    end; //if
    Counter:=0; //Counterを初期化
    for I:=0 to N do
    begin
        Counter:=Counter+Trunc( Random(2) ); //0または1をランダムに生成
    end; //for
    result:=Counter/N;
end; //function

exports //ここに列挙したものが外部に公開される。
    TossingCoin;
(*↑追加ここまで↑*)

begin
end
.

コードの詳細な説明を加えようと思ったのですが、質問の応需ということで逃げておきます。管理人としてもフィードバックが欲しいですし。(^_^;


コンパイル

[コンパイルの仕方の説明画像]『プロジェクト』から『tossing_coin_dllをコンパイル』を選択します。とくにミスが無ければ、そのまま、特に何も起きません。
もし、ミスがあると、『エラー』『警告』『ヒント』が出ますので、修正して下さい。
無事コンパイルが完了すると、プロジェクトを保存したフォルダに『tossing_coin_dll.dll』というファイルができているはずです。
『tossing_coin_dll.dll』システムフォルダにコピーしておいて下さい。(通常、Win9x/MeならC:\System\、Win NT/2k/xpではC:\System32\) 
※後で作成するVisual Basicのプロジェクトと同じフォルダにコピーしてもかまいません。(ただし、VBの開発環境からの実行では、DLLが見つからないと言ってきます。EXEを作成してから試す必要あり)


Visual Basicでのフォームのデザイン

では、まず、フォームのデザインから。(プロジェクトの種類は『標準EXE』)

Visual Basicでのフォームのデザイン(プロパティは抜粋)
[VBのフォームイメージ]
Form1(Caption="Tossing Coin",BorderStyle=3)
FrameDelphi(Caption="Delphi で作ったDLL")
lblDelphi(Alignment=1,BorderStyle=1)
btnDelphi(Caption="実行")
FrameVB(Caption="Visual Basic")
lblVB(Alignment=1,BorderStyle=1)
btnVB(Caption="実行")
 

Visual Basicでのコーディング

 ここからは、ふつうのAPI呼び出しと同じです。せっかくですから、VBでも同じ機能を持つ関数を作成して、速度を比較してみましょう。
 まず、それらのコードを、標準モジュールに記述しましょう。

コード(Visual Basic、mdlTossingCoin.bas)

Option Explicit
'Delphiで作成した関数の宣言(DelphiのInteger型は32bitなのでVBのLong型に相当する)
Public Declare Function TossingCoinDelphi Lib "tossing_coin_dll.dll" Alias "TossingCoin" (ByVal N As Long) As Double

'Delphiで作成した関数と同じ機能の関数をVBでも作成する
Public Function TossingCoinVB(N As Long) As Double
Dim I As Long '変数の宣言
Dim Counter As Long
    If N <= 0 Then 'ゼロ以下の時はエラーなので-1を返す。
        TossingCoinVB = -1
        Exit Function
    End If

    Counter = 0 'Counterを初期化VBでは無くても良い(自動的に初期化される)
    For I = 0 To N
        Counter = Counter + Int(Rnd() * 2)
    Next I
    TossingCoinVB = Counter / N
End Function

 つぎに、『btnDelphi』『btnVB』がクリックされたときの動作をフォームモジュールに記述します。

コード(Visual Basic、Form1.frm)

Option Explicit

Private Sub cmdDelphi_Click() 'Delphiで作ったDLLの関数に1000万回コインを投げさせる。
    lblDelphi.Caption = TossingCoinDelphi(10000000)
End Sub

Private Sub cmdVB_Click() 'VBで作った関数に1000万回コインを投げさせる。
    lblVB.Caption = TossingCoinVB(10000000)
End Sub

実行

 あとは、実行すれば、結果がラベルに表示されるはずです。『Delphi』の方が若干速いと思いますが、いかがだったでしょうか?「俺のPCはぴかぴかの最新型だから、どっちも一瞬で結果が出てしまって話にならん!」という人は関数に渡す引数の値を大きくしてみて下さい。

『実行』ボタンを押した瞬間に「実行エラー '48': ファイルが見つかりません。:tossing_coin_dll.dll」と表示された場合、つぎのことを確認して下さい。
  1. Delphiで作成したDLLはシステムフォルダあるいは、VBで保存したプロジェクトと同じフォルダにコピーしましたか?
  2. VBのプロジェクトと同じフォルダにコピーした場合、VBの統合環境からはうまくDLLが見つかりません。実行ファイルを作成してから試すか、システムフォルダにDLLをコピーし直してから試してみて下さい。


ご苦労様でした。言語の壁を超える気分はいかがだったでしょうか。
次回は、Delphiでコールバック機能の付いたDLLの作成に挑戦してみましょう。

<目次へ> <第二回へ>