二重起動防止でコマンドライン引数の受け渡しについて


のん吉  2005-04-02 20:34:31  No: 14073

二重起動を防止ししながら、コマンドラインの引数は既に起動中のフォームに送ろうとして、
次の様に作ってみましたが、※の箇所で"未定義の識別子エラー"となります。
定義の仕方の問題と思っておりますが、うまく行きません。
対処方法について教えて下さい。
*-------------------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.


通りすがり  2005-04-03 00:18:33  No: 14074

> ※の箇所で"未定義の識別子エラー"となります。
CopyDataToOldはTForm1のメソッドだから。


のん吉  2005-04-03 00:32:11  No: 14075

レスありがとうございます。
参考にしたHPではcopydatatooldの箇所の手続きを他のユニットにコードして・・・
とあったので、Form1で定義したのですが、これじゃだめという事で、
具体的に修正点など御教え頂けると幸いです。


通りすがり  2005-04-03 01:50:51  No: 14076

CopyDataToOldの中身をエラーの出る部分に書けばいいと思います。


のん吉  2005-04-03 06:04:48  No: 14077

実はその方法はすでに試して、動作済みです。
テスト用の小さなプログラムはそれでもよいのですが、
もう少し複雑な事を予定していますので、
根本的に解決しておく必要があるだろうと、
勉強をかねて質問させていただいております。


りおりお  2005-04-03 09:18:51  No: 14078

> 根本的に解決しておく

そもそもメソッドにする必要がないので、単なる関数にしてプロジェクトファイルに
書くだけです。それから、OpenMutex() を使うのは誤りです。根本的な解決を望むなら
その辺もちゃんとしましょう。


単純ミス  2005-04-03 11:02:20  No: 14079

>  CopyDataToOld(Wnd, Cmdline);  //※<-----ここで未定義識別子エラー
Form1のメソッドなんだから、
  Form1.CopyDataToOld(Wnd, Cmdline);


通りすがり  2005-04-03 11:24:08  No: 14080

> Form1のメソッドなんだから、
>   Form1.CopyDataToOld(Wnd, Cmdline);
このときTForm1のインスタンスはまだ生成されていないのでエラーになります。
Application.CreateForm(TForm1, Form1);よりも前なので。


kkk  2005-04-03 12:18:19  No: 14081

用途的にFomのメソッドでは良くないと思います
りおりおさんのおっしゃるように単なる関数にしたほうが良いでしょう。
別のファイルに分けたいのであればCopyDataToOldを含むユニットファイルを作成してプロジェクトのソースでusesに追加してください。

りおりおさんの
>OpenMutex() を使うのは誤りです
の説明。(あえて説明をしていらっしゃらないが)
OpenMutexだとクリティカルな問題が出てきますのでCreateMutexだけで2重起動をチェックしてください。(でよいのかな?)


善悪は別として  2005-04-03 13:33:38  No: 14082

>> Form1のメソッドなんだから、
>>   Form1.CopyDataToOld(Wnd, Cmdline);
>このときTForm1のインスタンスはまだ生成されていないのでエラーになります。
>Application.CreateForm(TForm1, Form1);よりも前なので。

クラス変数はそのクラスをCreateしなければ使えませんが、クラスメソッドは
コンパイルした時点で既にそのインスタンスが存在します。
なので、Createする前でもクラスメソッドを呼び出すことが出来ます。
エラーにはならず正常に動作します。


???  2005-04-03 18:06:53  No: 14083

>>> Form1のメソッドなんだから、
>>>   Form1.CopyDataToOld(Wnd, Cmdline);
>>このときTForm1のインスタンスはまだ生成されていないのでエラーになります。
>>Application.CreateForm(TForm1, Form1);よりも前なので。

>クラス変数はそのクラスをCreateしなければ使えませんが、クラスメソッドは
>コンパイルした時点で既にそのインスタンスが存在します。
>なので、Createする前でもクラスメソッドを呼び出すことが出来ます。
>エラーにはならず正常に動作します。

Createする前に呼び出しはできないでしょう。


論より証拠  2005-04-03 18:25:17  No: 14084

一番上のサンプルコードを動かしてみましょう。


???  2005-04-03 19:06:51  No: 14085

Createする前に Form1.CopyDataToOldを呼び出した場合
Form1.CopyDataToOldにブレークポイントを設定してステップ実行してみるとわかると思いますがCopyDataToOldにエントリした時点でvar Form1:TFormにはまだ値が入っていません(nil)。当たり前ですが
プログラムは自体は当然コンパイル時に存在しますが、有効なインスタンスはCreate後でなければ作成されていません。
ルーチン内で未初期化の変数を偶然使用していなければ一見正常に動作しているように見えますが誤りです。
これは善悪の問題ではなくて間違った使用方法です。


???  2005-04-03 19:22:55  No: 14086

補足
上のサンプルでCreate前にForm1.CopyDataToOldを実行してもエラーとならないのは
たまたまCopyDataToOldの中でそのクラスに関する変数を利用していないからです。
だからといって問題ない使用方法とはいえません。


絶対条件  2005-04-03 19:42:29  No: 14087

>たまたまCopyDataToOldの中でそのクラスに関する変数を利用していないからです。
その通りです。
Createする前にクラス変数は使えません。


のん吉  2005-04-03 19:49:41  No: 14088

たくさんのレスありがとうございます。
皆さんからのアドバイスを参考に、今から直してみます。


りおりお  2005-04-04 00:28:32  No: 14089

> コンパイルした時点で既にそのインスタンスが存在します。
> なので、Createする前でもクラスメソッドを呼び出すことが出来ます。

そうです。でも、クラスメソッドは class っていう宣言が必要ですけど。
でも、普通のメソッドはインスタンス生成前は使えません。使えたとしても偶然、という
ことです。

クラスメソッドはインスタンスではなく、クラスを参照にして呼び出します。
フォームに一つも TListBox がなくても、以下は正しい文法です。

procedure TForm1.Button1Click(Sender: TObject);
begin
  Caption := TListBox.ClassName;
end;


りおりお  2005-04-04 00:29:21  No: 14090

> コンパイルした時点で既にそのインスタンスが存在します。

これは明らかに間違いです。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加