お知らせ

電子会議

ライブラリ

FDelphi サイト全文検索

Delphi FAQ一覧

サンプル蔵



FDelphi FAQ
15番会議室「FAQ編纂委員会」に寄せられた「よくある質問の答え」

[Q]
二重起動防止して、実行ファイルのショートカットアイコンなどに、たくさ んのファイルをまとめてドロップして再起動する場合、それらのファイル名 だけは旧モジュールに送信したいのですが、どうすればいいでしょう?

[A]
ショートカットにまとめてドロップできるファイル数は、全体の長さが516
文字ですから、パスの長さにもよりますが、せいぜい数10個です。グローバ
ルアトム1個で送信できる文字列は、255字ですので、最低 2個必要になりま
す。

>'ク'  RE:[FAQ] ParamStr(i)全体の長さ制限

にありますように、コマンドライン文字数の最大値は516ですが、以下の例で
複数ファイルをドラッグ&ドロップする場合は、パスは同じですので、
ParamCount>=2 のとき、ParamStr(2)以降はパス名なしで設定できて、送る文
字数を大幅に削れます。ParamCount=1 のときも、実行ファイル自体、フルパ
スを限度に近く取るのは問題が多そうです。例えば、エクスプローラでショ
ートカットを作るのに、実行ファイルのフルパスは 238 文字が限度でした。
これを1文字でも越えるとショートカットが作成できませんでした。さらに、
ParamStr(i) の許容長は256文字ですので、以上から、ドラッグ&ドロップで
の送信文字列長は、グローバルアトム2個、510文字で十分と思われます。

 以下の例では、これをまとめて送信しています。ヒントは

>[FAQ]二重起動防止でパラメータ送信(1)

の、【補足】(4)にあります。つまり、2個の場合、

    SendMessage(Wnd,MsgID,WPARAM(anAtom1),LPARAM(anAtom2)); // (***)
    aAtom1:=LOWORD(Msg.wParam);   // (***) に対応
    aAtom2:=LOWORD(Msg.lParam);

 で、送受信できます。別のやり方は、

    SendMessage(Wnd,MsgID,MakeLong(anAtom1,anAtom2),0); // (***)
    aAtom1:=LOWORD(Msg.wParam);   // (***) に対応
    aAtom2:=HIWORD(Msg.wParam);

 あるいは、

    SendMessage(Wnd,MsgID,0,MakeLong(anAtom1,anAtom2)); // (***)
    aAtom1:=LOWORD(Msg.lParam);   // (***) に対応
    aAtom2:=HIWORD(Msg.lParam);

 です。

 このようなことから、今回のケースでは必要ありませんが、

    SendMessage(Wnd,MsgID,
      MakeLong(anAtom1,anAtom2),MakeLong(anAtom3,anAtom4)); // (***)
    aAtom1:=LOWORD(Msg.wParam);   // (***) に対応
    aAtom2:=HIWORD(Msg.wParam);
     aAtom3:=LOWORD(Msg.lParam);
     aAtom4:=HIWORD(Msg.lParam);

 で、4つのアトムまでまとめて送受信できることが予想されます。
[例]
 まず、プロジェクトソースに、

>#22 SGM02275 七☆星 さん、[FAQ]Delphi2.0(Win32)での二重起動の防止

のコードを入れます。そのうち、再起動時の部分、

    Wnd:=FindWindow('TAtoms2F',nil);  // (**)
    {クラス名で既にオーフ゜ンされているフォームを探します}
    if Wnd<>0 then begin
      {TApplicationのウィント゛ウハント゛ルを取得}
      SetForegroundWindow(Wnd); {前面に移動してアクティフ゛化}
      if ParamCount>0 then
         // (*) グローバルアトム設定と旧モジュールへの送信
        PutGlobalAtom2(Wnd,ParamCount,sUniqueName);

   ここでは、別ユニットに、(*)の手続き PutAGlobalAtom2() をコードし、
それを使っています。その内容は、

{=========================================================}
procedure PutGlobalAtom2(
          Wnd: HWnd;       {旧モジュールウィンドウハンドル}
          aParamCount: integer; {ドロップファイル数}
          aUnique: string);{登録メッセージ}
var
  pcAtom1,pcAtom2: PChar;
  anAtom1,anAtom2: TAtom;
  MsgID: UINT;

  {-------------------------------------------------------}
  procedure GAddAtom(var anAtom1,anAtom2: TAtom;
                     pc1,pc2: PChar;
                     var ID: UINT);
  begin
    pc2:=nil;
    if (StrLen(pc1)>AMAX_BUF) then
      pc2:=pc1+AMAX_BUF;        {pc1後半をポイント}
    anAtom2:=GlobalAddAtom(pc2);{グローバルアトムテーブルに格納}
    if (StrLen(pc1)>AMAX_BUF) then
      pc1[AMAX_BUF]:=#0;        {pc1後半を殺す}
    anAtom1:=GlobalAddAtom(pc1);{グローバルアトムテーブルに格納}
    ID:=RegisterWindowMessage(PChar(aUnique));
    if (anAtom1<>INVALID_ATOM) then begin
      SendMessage(Wnd,ID,WPARAM(anAtom1),LPARAM(anAtom2));
      //SendMessage(Wnd,ID,MakeLong(anAtom1,anAtom2),0);
        {アトム2つで32-bitのlongint値を作って送信}
    end;
    GlobalDeleteAtom(anAtom1); {ク゛ローハ゛ルアトム参照数を1減らす}
    GlobalDeleteAtom(anAtom2);
  end; {GAddAtom}

{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
{PutGlobalAtom2}
begin
  pcAtom1:=StrAlloc(AMAX_BUF*2+1);

  {以下は何をしているかというと、ドロップされたファイル名を、
   一旦pcAtom1に入れ、256文字以上のとき、後半をpcAtom2でポ
   イントする。
   パスは同じと考え、最初のファイル名だけはフルパス、残りは
   ファイル名だけで、ファイル名の間に区切り記号として'|'を
   入れている。}
  ParamsToData(aParamCount,pcAtom1);
  GAddAtom(anAtom1,anAtom2,pcAtom1,pcAtom2,MsgID);

  StrDispose(pcAtom1);
end; {PutGlobalAtom2}

{=========================================================}
procedure ParamsToData(
          aParamCount: integer;  {=ParamCount}
          var pcData: PChar);    {収納変数}
(ここでは略)

 そして受信側のフォーム、ここでは、(**)で指定したように、
Atoms2F フォームですが、ListBox1を配置しています。そのフォームインス
タンスの宣言部で、

type
  TAtoms2F = class(TForm)
    ListBox1: TListBox;
(...略...)
  private
    { Private 宣言 }
(...略...)
  protected
    procedure WndProc(var Msg: TMessage); override;
  public
    { Public 宣言 }
(...略...)

と、WndProcをオーバーライドします。この内容は、

{=========================================================}
procedure TAtoms2F.WndProc(var Msg: TMessage);
var
  aAtom1,aAtom2: TAtom;
  MsgID: UINT;
begin
  MsgID:=RegisterWindowMessage(sUniqueName);
         {アプリ間通信済みメッセージの取り出し}
  if Msg.Msg=MsgID then begin
    aAtom1:=LoWord(Msg.wParam); // (***)に対応
    aAtom2:=LoWord(Msg.lParam);

    if GlobalGetAtomName(aAtom1,pcAtom1,AMAX_BUF+1)<>0 then
      begin
      StringList1.Clear;
      if aAtom2=0 then begin
        DropedStrs(pcAtom1);
        DragedToListBox1;
      end else
        pcAtom2:=StrEnd(pcAtom1); {pcAtom1末尾ポインタ}
    end;
    if GlobalGetAtomName(aAtom2,pcAtom2,AMAX_BUF+1)<>0 then
      begin
      DropedStrs(pcAtom1);
      DragedToListBox1;
    end;
  end;
  inherited WndProc(Msg);
end; {TAtoms2F.WndProc}

{=========================================================}
{受信文字列を'|'で分解して、ロングネームでStringList1に放り込み}
procedure TAtoms2F.DropedStrs(pcDat: PChar);
(...略...)

{=========================================================}
{StringList1のファイルを、重複しないようにListBox1にアペンド}
procedure TAtoms2F.DragedToListBox1;
(...略...)

【補足】
 (1) このままだと未定義になる変数は、外部で適当に定義して下さい。
他の未定義関数は、他の[FAQ]中に見つかると思います。

 (2) プロジェクトソースは、次のユニットをusesしてあれば十分です。
  Windows,Classes,Messages,Dialogs,Forms,SysUtils,

 (3) GlobalGetAtomName(aAtom1,pcAtom1,AMAX_BUF+1) ですが、APIバイブ
ルをよく読むと、第3引数は、第2引数にコピーする最大文字数、となってい
ます。例にも、バッファーを33文字確保して、GlobalGetAtomName(.., .., 
32)というのがあったため、しまったと思い、一度訂正を入れたのですが、実
際に試すと、そうではなく、最大文字数+1 が必要でした。


ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum FDELPHIに寄せられる質問の中から、よくある質問への回答を FDELPHIのメンバーがまとめたものです。 したがって、これらの回答はボーランド株式会社がサポートする公式のものではなく、掲示されている内容についての問い合わせは受けられない場合があります。

Copyright 1996-1998 Delphi Users' ForumFAQ編纂委員会