二重起動を防止ししながら、コマンドラインの引数は既に起動中のフォームに送ろうとして、
次の様に作ってみましたが、※の箇所で"未定義の識別子エラー"となります。
定義の仕方の問題と思っておりますが、うまく行きません。
対処方法について教えて下さい。
*-------------------Project source-----------------------*
program tushinn;
uses
Forms,
Windows,Classes, Messages, Dialogs, SysUtils,
tushinn_unit1 in 'tushinn_unit1.pas' {Form1};
{$R *.res}
var
mx : THANDLE;
Wnd, AppWnd: HWnd;
begin
mx := OpenMutex(MUTEX_ALL_ACCESS, false, 'nonkichisoft');
if mx<>0 then begin
Wnd := FindWindow('TForm1', nil);
if Wnd <> 0 then
begin
SetForegroundWindow(Wnd);
if paramcount>0 then
CopyDataToOld(Wnd, Cmdline); //※<-----ここで未定義識別子エラー
end;
CloseHandle(mx);
exit;
end;
mx := CreateMutex(nil,false,'nonkichisoft');
application.Initialize;
Application.CreateForm(TForm1, Form1);
application.Run;
ReleaseMutex(mx);
end.
*-----------unit------------------------------------------*
unit tushinn_unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComObj;
type
TForm1 = class(TForm)
Memo1: TMemo;
private
{ Private 宣言 }
public
{ Public 宣言 }
procedure WMcopydata(var msg: TWMCopyData);message WM_COPYDATA;
procedure CopyDatatoOld( Wnd: HWnd; aCmdline: string);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.WMCopyData(var msg: TWMCopyData);
var
buf: Pchar;
begin
if msg.CopyDataStruct.dwData=0 then
begin
buf := StrAlloc(msg.CopyDataStruct.cbData);
try
StrCopy(buf, msg.CopyDataStruct.lpData);
Memo1.Lines.Text := buf;
finally
StrDispose(buf);
end;
end
else
inherited;
end;
procedure TForm1.Copydatatoold(Wnd: HWnd;
aCmdline: string);
var
//pcdata : PChar;
cd : TCopyDataStruct;
begin
cd.cbdata := length(aCmdline)+1;
cd.lpdata := stralloc(cd.cbdata);
try
strcopy(cd.lpdata, pchar(acmdline));
sendmessage(Wnd, WM_COPYDATA,0,lparam(@cd));
finally
strdispose(cd.lpdata);
end;
end;
end.
> ※の箇所で"未定義の識別子エラー"となります。
CopyDataToOldはTForm1のメソッドだから。
レスありがとうございます。
参考にしたHPではcopydatatooldの箇所の手続きを他のユニットにコードして・・・
とあったので、Form1で定義したのですが、これじゃだめという事で、
具体的に修正点など御教え頂けると幸いです。
CopyDataToOldの中身をエラーの出る部分に書けばいいと思います。
実はその方法はすでに試して、動作済みです。
テスト用の小さなプログラムはそれでもよいのですが、
もう少し複雑な事を予定していますので、
根本的に解決しておく必要があるだろうと、
勉強をかねて質問させていただいております。
> 根本的に解決しておく
そもそもメソッドにする必要がないので、単なる関数にしてプロジェクトファイルに
書くだけです。それから、OpenMutex() を使うのは誤りです。根本的な解決を望むなら
その辺もちゃんとしましょう。
> CopyDataToOld(Wnd, Cmdline); //※<-----ここで未定義識別子エラー
Form1のメソッドなんだから、
Form1.CopyDataToOld(Wnd, Cmdline);
> Form1のメソッドなんだから、
> Form1.CopyDataToOld(Wnd, Cmdline);
このときTForm1のインスタンスはまだ生成されていないのでエラーになります。
Application.CreateForm(TForm1, Form1);よりも前なので。
用途的にFomのメソッドでは良くないと思います
りおりおさんのおっしゃるように単なる関数にしたほうが良いでしょう。
別のファイルに分けたいのであればCopyDataToOldを含むユニットファイルを作成してプロジェクトのソースでusesに追加してください。
りおりおさんの
>OpenMutex() を使うのは誤りです
の説明。(あえて説明をしていらっしゃらないが)
OpenMutexだとクリティカルな問題が出てきますのでCreateMutexだけで2重起動をチェックしてください。(でよいのかな?)
>> Form1のメソッドなんだから、
>> Form1.CopyDataToOld(Wnd, Cmdline);
>このときTForm1のインスタンスはまだ生成されていないのでエラーになります。
>Application.CreateForm(TForm1, Form1);よりも前なので。
クラス変数はそのクラスをCreateしなければ使えませんが、クラスメソッドは
コンパイルした時点で既にそのインスタンスが存在します。
なので、Createする前でもクラスメソッドを呼び出すことが出来ます。
エラーにはならず正常に動作します。
>>> Form1のメソッドなんだから、
>>> Form1.CopyDataToOld(Wnd, Cmdline);
>>このときTForm1のインスタンスはまだ生成されていないのでエラーになります。
>>Application.CreateForm(TForm1, Form1);よりも前なので。
>クラス変数はそのクラスをCreateしなければ使えませんが、クラスメソッドは
>コンパイルした時点で既にそのインスタンスが存在します。
>なので、Createする前でもクラスメソッドを呼び出すことが出来ます。
>エラーにはならず正常に動作します。
Createする前に呼び出しはできないでしょう。
一番上のサンプルコードを動かしてみましょう。
Createする前に Form1.CopyDataToOldを呼び出した場合
Form1.CopyDataToOldにブレークポイントを設定してステップ実行してみるとわかると思いますがCopyDataToOldにエントリした時点でvar Form1:TFormにはまだ値が入っていません(nil)。当たり前ですが
プログラムは自体は当然コンパイル時に存在しますが、有効なインスタンスはCreate後でなければ作成されていません。
ルーチン内で未初期化の変数を偶然使用していなければ一見正常に動作しているように見えますが誤りです。
これは善悪の問題ではなくて間違った使用方法です。
補足
上のサンプルでCreate前にForm1.CopyDataToOldを実行してもエラーとならないのは
たまたまCopyDataToOldの中でそのクラスに関する変数を利用していないからです。
だからといって問題ない使用方法とはいえません。
>たまたまCopyDataToOldの中でそのクラスに関する変数を利用していないからです。
その通りです。
Createする前にクラス変数は使えません。
たくさんのレスありがとうございます。
皆さんからのアドバイスを参考に、今から直してみます。
> コンパイルした時点で既にそのインスタンスが存在します。
> なので、Createする前でもクラスメソッドを呼び出すことが出来ます。
そうです。でも、クラスメソッドは class っていう宣言が必要ですけど。
でも、普通のメソッドはインスタンス生成前は使えません。使えたとしても偶然、という
ことです。
クラスメソッドはインスタンスではなく、クラスを参照にして呼び出します。
フォームに一つも TListBox がなくても、以下は正しい文法です。
procedure TForm1.Button1Click(Sender: TObject);
begin
Caption := TListBox.ClassName;
end;
> コンパイルした時点で既にそのインスタンスが存在します。
これは明らかに間違いです。
ツイート | ![]() |