DELLファイルの勉強を始めました。
DELLと実行ファイルの間でテキストメッセージのやり取りをしたいと考えています。
最終的にはアプリからメッセージをDELLに送り、
DELLに音声をしゃべらせます。
そしてDELLがInteger型の数値を貰うと、
中断したり再開したりするようにしたいと考えています。
DELLの簡単なサンプルは作れたのですが、
手持ちの参考書にはメッセージのやりとりのサンプルがなく、
質問させていただいた次第です。
どうかお知恵の拝借よろしくお願いします。m(__)m
DELLって、もしかしてDLLの事でしょうか?
であれば、DLLに対してWindowメッセージを送ることもできるでしょうけど
このような場合であれば、それぞれの関数を用意すればいいんじゃないでしょうか。
例えば、しゃべらせるには"TalkText(const Message: string)"関数とか
中断するには"Pause(const Flag: integer)"で、Flagが0なら中断、1なら再開…みたいに。
Questさんありがとうございます、
返信遅れました。
そうですDLLです。
間違えました^^;。
色々やってテキストのやりとりまでは成功しました。
が、コンポーネントの貼り付け(生成?)が判りません。
アクティブXコンポーネントを使ってDLLにしゃべらせたいと思ってます。
DLL側ソース
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
end;
function speak (s:string): string; stdcall;
begin
Result := s;
end;
exports
speak;
end.
実行側ソース
function speak (s:string): string;
stdcall; external 'dll.dll';
procedure TForm1.Button1Click(Sender: TObject);
begin
edit1.Text := speak('aiueo');
end;
DLL内部でやった事はありませんが、通常のEXEの中では動的に
ActiveXコンポを生成して使用したことはありますので
同じようにすれば良いのではないでしょうか?
ちょっと乱暴ですが
function speak (s:string): string; stdcall;
var
ActiveX: THogeHoge;
begin
ActiveX := THogeHoge.Create(nil);
try
ActiveX.Speak(s);
finally
ActiveX.Free;
end;
Result := s;
end;
こんな感じでしょうか。
ActiveX: THogeHoge; <=この部分は、通常のフォームにActiveXを
貼り付けたときに自動的に宣言されるものをコピペします。
返信遅れました。
参考書を頼りに以下まで何とか出来ました。
実行すると何とかしゃべるのですが、
その後でエラーが出ます。
「一度に多数の例外が発生しました。
'access vioation at 0x00151316a: read of address 0x01ad3fa4'」
となります。
以下がソースです。
よろしくお願いします。
DLL2.PDR
uses
SysUtils,
Classes,
Unit3 in 'Unit3.pas' {Form1};
{$R *.res}
exports
ShowForm index 1,
speak index 2;
begin
end.
DLLフォーム部
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, OleCtrls, HTTSLib_TLB, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
TextToSpeech1: TTextToSpeech;
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
procedure ShowForm; export; stdcall;
function speak (s:string): string; stdcall;
var
Form1: TForm1;
s1:string;
implementation
{$R *.dfm}
procedure ShowForm;
begin
try
Form1 := TForm1.Create(Application);
Form1.Show;
except
end;
end;
function speak (s:string): string; stdcall;
begin
s1 := s;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
form1.TextToSpeech1.Speak(s1);
timer1.Enabled := false;
end;
DLL呼び出し部
unit Unit4;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
procedure ShowForm; stdcall;
function speak (s:string): string; stdcall;
const
Dll2 = 'Dll2.Dll';
procedure ShowForm; external Dll2 index 1;
function speak; external Dll2 index 2;
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
try
speak(edit1.Text);
ShowForm;
except
end;
end;
end.
exeとDLLの間で長い文字列(String型)を受け渡しする場合は
双方でusesの先頭に'ShareMem'を入れておく必要があります。
(さらにBORLANDMM.DLLを一緒に配布しなくてはなりません)
詳しくはヘルプで「共有メモリマネージャ」を調べてください。
短い文字列かPCharを使えば、そのような制限はありません。
(ただし、PCharを返すような場合は自分で適切にメモリ管理を行なう必要があります)
function speak(s: PChar): PChar; stdcall;
...
speak(PChar(edit1.Text));
提示されたコードだとspeakは何も返していないようなので、procedureでいいのではないかと思いますが……
Questさん torさん ありがとうございます。
ShareMemを追加ても、エラーが出ました。
「無効なポイント操作」
「Runtime error 217 at 00413710」
と出て、次に
「一度に多数の例外が発生しました。
'access vioation at 0x00151316a: read of address 0x01ad3fa4'」
となります。
speakですが、参考書を頼りに継ぎ接ぎで
自分でもよく判らず組んでるので、こんがらがってる次第です^^;
エラーは、フォームの呼び出しで起きてるみたいです。
スピーチアクティブXコンポーネントと、
テキストのやりとりをしなくても、
フォームを閉じた時に上記のエラーが出ました。
何が原因なのでしょうか??
ご指導よろしくお願いしますm(__)”m。
フォーム付きDLLを作ったことが無かったので少し試してみました。
ぱっと試した感じでは、DLL側のフォームは明示的にFreeしてやる必要があるのでは?
exe側をCloseする時にDLL内の
procedure CloseForm;
begin
Form3.Free;
end;
みたいなの書いて実行させてやってみてください。
monaaさんありがとうございます。
Form.Freeを入れても同じでした。
TextToSpeech1.Freeを入れたところ、発音直後のエラーは消えました。
しかし、プログラム終了時にエラーが発生します。
色々試したら、エラーの元が特定出来ました!
function speak (s:string): string; stdcall;
begin
s1 := s;
end;
このfunctionを実行してテキストのやりとりをすると、エラーになるようです。
試しにS1を'aaa'に変えたところ、「無効なポインタ操作」エラーも出ず、問題なくしゃべり、エラーも起きませんでした。
このfunctionを使わずに文字列のやりとりをする方法、
又はエラーをなくす方法はないでしょうか??
よろしくお願いしますm(__)”m。
まさに長い文字列の受け渡しによる問題に見えますが
先に提案したPCharを使う方法は試してみましたか?
> ShareMemを追加ても、エラーが出ました。
ShareMemを使う場合「DLLとそれを使うアプリケーションの両方で」「usesの一番最初に」指定しなくてはいけないとありますが
実際のコードはその通りになっていたでしょうか。
torさんありがとうございます、無事解決しました。
ソースがこんがらがったのでサンプルを直接いじって色々試行錯誤してました^^;。
ShareMemは・・・、忘れてました^^;
でもShareMemを先頭に追加しても、こちらではエラーなりました。
「無効なポインタ操作」となります。
環境は、Vista、Delphi7Pro、です。
Pcherで受け渡しする方法で無事解決しました。
改めてありがとうございますm(__)m。
以下がソースです。
DLLソース:
library DllForm;
{ DLL メモリ マネージャ について:
もしこの DLL が引数や返り値として String 型を使う関数や手続きを
エクスポートする場合、以下の USES 節とこの DLL を使うプロジェクト ソースの
USES 節の両方に、最初に現れるユニットとして ShareMem を指定しなけれ
ばなりません。
これは構造体やクラスに埋め込まれている場合も含め String 型を DLL
とやり取りする場合に必ず必要となります。
ShareMem は共用メモリマネージャである DELPHIMM.DLL とのインターフェース
です。あなたの DLL と一緒に配布する必要があります。
DELPHIMM.DLL を使うのを避けるには、PChar または ShortString 型を
使って文字列のやり取りをおこなってください。}
uses
//ShareMem,
SysUtils,
Classes,
Dialogs,
DLLMAIN in 'DLLMAIN.PAS' {SubForm};
exports // エクスポート関数の定義
ShowForm index 1, // ShowModalメソッドでの表示
speak index 2;
begin
end.
DLLフォーム部:
unit DllMain;
interface
uses
{ShareMem, }Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, OleCtrls, HTTSLib_TLB, ExtCtrls;
type
TSubForm = class(TForm)
Button1: TButton;
TextToSpeech1: TTextToSpeech;
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
public
{ Public 宣言 }
end;
procedure ShowForm; export; stdcall; // モード付きフォームの表示
function speak (s:string): string; stdcall;
var
SubForm: TSubForm;
s1:string;
implementation
{$R *.DFM}
{ フォームの表示処理 }
procedure ShowForm;
begin
try
Application.CreateForm(TSubForm, SubForm); // フォームの作成
SubForm.ShowModal; // モード付き表示
finally
SubForm.Free; // メモリなどの解放
end;
end;
function speak (s:string): string; stdcall;
begin
s1 := PChar(s);
end;
procedure TSubForm.Timer1Timer(Sender: TObject);
begin
TextToSpeech1.Speak(s1);
timer1.Enabled := false;
end;
procedure TSubForm.Button1Click(Sender: TObject);
begin
TextToSpeech1.Free;
close;
end;
end.
DLL呼び出し側プロジェクトファイル
unit DllInt;
interface
procedure ShowForm; stdcall;
function speak (s:string): string; stdcall;
implementation
const
DllForm = 'DllForm.Dll';
procedure ShowForm; external DllForm index 1;
function speak (s:string): string; external DllForm index 2;
end.
DLL呼び出し側フォームソースファイル
unit Main;
interface
uses
{ShareMem, }Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls,
DllInt;
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
speak(PChar(edit1.Text));
ShowForm;
end;
end.
ツイート | ![]() |