Timerで呼び出したウィンドウのEinvalidoperationをなくす方法は?


As  2012-05-18 20:02:12  No: 42221

2009では問題のなかったプログラムですが、XE2でコンパイルするとこのエラーが出ます。

このTimerで呼び出したウィンドウの中でも、Timerを使って作業をさせていますが、このときエラーになるようです。
手動(ボタン)で同じウィンドウを操作する時はエラーになりませんので。

この問題を避けるために、呼び出したウィンドウの中でOnActivateで作業させると仕事はするのですが、ウィンドウがいくつも立ち上がるという問題が生じました。

私の知識では、お手上げです。
どうかよろしくお願いします。


Quest  2012-05-18 21:36:30  No: 42222

OnActivateで試したという事で、起動時に1回だけ該当のウィンドウを表示したいという前提で。
呼び出し元のフォームのprivateあたりにフラグを宣言して
OnActivateでこのウィンドウを呼び出したらフラグを立てて
2度目には表示しないってのが一番簡単かな。
フラグを論理型でなく数値にすれば、その値でウィンドウを開くかどうか
判断したりすることもできます。

ん、タイマーを使って呼び出すとき、Intervalの値はいくつくらいでしょうか?
その値によっては、OnTimerイベントですぐにEnabledをFalseにしないと
同じウィンドウを何度も開こうとしますが。
でも、2009では動いてたんだから、その辺は処理済でしょうけど。


As  2012-05-18 23:45:43  No: 42223

Questさん、ありがとうございます。

まず,Intervalは60000にしています。まあ、これは問題ないと思います。

次に、フラグを立てる件ですが、これは変数を使って制御しているんですが、まったく役立ちません。

なんか、想像なんですが、呼び出されたformのonactivateが終わったら元のformに信号が帰って、formを作るのをやめるとか?
OnActivateで作業させると、その信号が来ないのでいくつもできるのかなとか??

参考ですが、OnCreate、OnShow、OnActivateの順で実行されるようで、OnShow内で作業させると、呼び出されたFormが立ち上がりません。


Quest  2012-05-19 00:57:00  No: 42224

>フラグを立てる件ですが、これは変数を使って制御しているんですが、まったく役立ちません。
具体的にはどのようにしているんでしょう?
変数はどこで宣言していますか?

Type
  TForm1 = class(TForm)
    procedure FormActivate(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    Flag: integer;
    .
    .
    .
procedure TForm1.FormCreate(Sender: TObject);
begin
  Flag := 0
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
  if Flag = 0 then
  begin
    Flag := 1;
    //別ウィンドウを表示
  end
end
とすれば、一回だけ表示されるはずですが。


As  2012-05-19 09:44:42  No: 42225

Questさん、こんばんは。
お世話になります。

次のようにしていましたが、いくつも(最大8個位?)立ち上がりました。
timestepは別formで定義していて、usesを使って呼び出しています。

procedure form1.timer1timer(Sender:TObject);
begin
  if timestep=1 then 
  begin
   timestep:=2;
   //form2呼び出し
  end;
  以下呼び出しで取得したデータの処理

end;

呼び出したForm2で,onActivateを使って作業させると、作業できるんですが、いくつもform2が立ち上がります。

呼び出したForm2で、Timerを使って作業をさせようとすると
EInValidOperation のエラーが出ます。

よろしくお願いします。


As  2012-05-19 09:56:34  No: 42226

Timer1.Enabled:=false;
Timestep:=1;
はIf文の前に置いています。


Nov  2012-05-19 20:39:14  No: 42227

//form2呼び出し
のところで、具体的に何をしているのかがすご〜く気になります。
文脈から、意図的に複数のForm2のインスタンスを生成しているわけでは
なさそうですが、直接的または間接的にCreateFormしている気配がありますね...
>いくつもform2が立ち上がります。
文字どおりに捉えると、明らかに複数のForm2のインスタンスが生成されているかと。
その辺が明らかにならないと先に進めない気がします(個人的な意見です)。


  2012-05-19 21:28:37  No: 42228

断片的な情報とあやふやな表現の連続では、何もわからないと思います。
一度コードを挙げてみては。


Quest  2012-05-20 00:43:18  No: 42229

もしかして、Form2の中でもForm2を表示しようといていませんか?
また、Form1の"if timestep=1 then "の行にブレークポイントを置いて
2度目以降にここで止まったとき、timestepがちゃんと2になっているでしょうか?
いずれにしても、他の方が仰る様に該当部分のコードや
全体としてどういった動きにしたいのかを挙げてはいかがでしょう。

1.Form1作成、表示
2.Form1のOnActiveあるいはOntimerでForm2を作成、表示(たぶんモーダル)
3.Form2で作業した結果情報を使い、Form1で続きの作業を実行
といった流れではないかと想像していますが。


As  2012-05-20 07:44:41  No: 42230

簡単なプログラムを組んでみました。
form2には、edit1、button1、button2を配置しました。
これは、1個だけしか立ち上がりません。

実際に使っているFormは、richedit,memo,timer1,timer2,IdHTTPを配置しています。これは、作業をmemoにHellowを表示させるだけにしても、いくつも立ちがります。

とくに、IdHTTPはサブにもありますので、これを省いてやってみます。

また、報告します。


As  2012-05-20 09:03:27  No: 42231

Timer1,timer2,IdHTTPを除いてやってみましたが、hellowを表示するだけのプログラムでも、駄目でした。いくつも立ち上がります。
また、memoとbutton1,2だけにしても、いくつも立ち上がります。

もう今日はやめます。

EInValidOperationの解消法を考えたほうがいいかなと思います。

Questさん、いつもありがとうございます。
上に書いたように、hellowを表示するだけのプログラムでもいくつも立ち上がるので、作ったりはしていません。


As  2012-05-20 17:38:56  No: 42232

原因が分かりました。
ネットに接続するプログラムが問題です。

作った簡単なプログラムのform2をプログラムに組み込んで、徐々に問題になっているFormと同じにしていきました。
ネットに接続するプログラムを組み込んだら、いくつも立ちあがるようになりました。
その後、ネットに接続するプログラムを削除してHellowを表示させるようにしても、いくつも立ち上がります。

2009ではネットに接続するプログラムの多重起動ができなくなりましたが、
XE2では多重起動させるようになったのですかね。
まあ、ボタンでもできますし、いくつも立ちがるのを我慢すれば、問題はありませんし。
いくつも立ち上がりますが、そのうちの1つだけがその後のデータ処理プログラムにつながり、他のは関係ないのです。

次は、EInValidOperationもネット接続プログラムと関係しているのか調べてみます。


As  2012-05-20 20:15:47  No: 42233

簡単なプログラムのForm2にネット接続プログラムを入れても、EInValidOperationのエラーは出ませんでした。
ただ、いくつも立ち上がるのは前と同じでした。

で、元のプログラムではEInValidOperationのエラーはやはり出ます。

ハッカー対策で、自動でネットに接続するのは禁じられてるんだと理解して、ボタンで対応することにしました。

解決にはしませんので、対応策をご存じの方がおられましたら、回答をお願います。


というか  2012-05-21 05:37:24  No: 42234

こんな漠然とした表現では誰も解決できないと思うよ。


どっちやねん?  2012-05-21 16:30:46  No: 42235

>Timer1,timer2,IdHTTPを除いてやってみましたが、hellowを表示するだけのプログラムでも、駄目でした。いくつも立ち上がります。

>ネットに接続するプログラムを組み込んだら、いくつも立ちあがるようになりました。


KHE00221  2012-05-22 15:48:38  No: 42236

そもそも どの EInValidOperation が出てるんだ?

Vcl.Forms で使用しているので

//SParentRequired = 'コントロール '#39'%s'#39' は親ウィンドウを持っていません';
//SMDIChildNotVisible = 'MDI 子フォームは非表示にできません';
//SDuplicateMenus = 'メニュー '#39'%s'#39' は別のフォームで既に使われています';
//SNoMDIForm = 'フォームを作成できません。現在アクティブな MDI フォームはありません';
//SCannotFocus = '無効/非表示ウィンドウにはフォーカスを設定できません';
//SVisibleChanged = 'OnShow や OnHide では Visible を変更できません';

こんだけあるけど

とりあえず、再現できるソースを・・・


As  2012-05-25 09:18:03  No: 42237

どっちやねん?さん
>ネットに接続するプログラムを組み込んだら、いくつも立ちあがるようになりました。
→これは、1つしか立ち上がらないFormに、組み込んだらいくつも立ち上がるようになったという意味です。

>Timer1,timer2,IdHTTPを除いてやってみましたが、hellowを表示するだけのプログラムでも、駄目でした。いくつも立ち上がります。
→これは、いくつも立ち上がるとうになったFormから削除しても、立ち上がります。という意味です。

KHE00221 さん、ありがとうございます。
私も、EInVakidOPerationをどうしたらなくせるかで、質問したんですが、やっとそれを理解していただいてありがとうございます。

//SCannotFocus = '無効/非表示ウィンドウにはフォーカスを設定できません';

これが、出ます。
とにかく、2009ではまともに動いていたのです。
XE2でコンパイルしたら、エラーが出ますので、困ってます。
いくつも立ち上がるようになると、このエラーはでません。
このエラーが出るときには、立ち上がりません。
ソースについては、本物は複雑すぎてここには表示できないと思います。
で、作った簡単なプログラムを次の投稿で載せますが、ネット関連のプログラムは組み込めないので、エラーは起きません。
IdHTTPを使って、ネット接続のプログラムを組んでみてください。

Ontimerを使わないようにしたので、今は何の問題もありません。
OnTimerを使っていた時より、使い勝手が良くなったような気がします。

XE2に関しては、恐らくですが、もう質問することもないと思います。

皆さん、ありがとうございました。


As  2012-05-25 09:50:01  No: 42238

Form1(IndexMain)です。
procedure TIndexMain.Button1Click(Sender: TObject);
begin
       Making:=TPMaking.Create(Application);
       Making.ShowModal;
       Making.update;
end;

procedure TIndexMain.Button2Click(Sender: TObject);
begin
close;
end;

procedure TIndexMain.onActivate(Sender: TObject);
begin
  Edit1.text:='';
  timer1.interval:=1000;
  TimeStep:=0;
  TradeOn:=0;
  Timer1.Enabled := false;
end;

procedure TIndexMain.OnKeyPress(Sender: TObject; var Key: Char);
var
  s:string;
begin
 if key=char(13) then
  begin
   s:=Edit1.text;

   if S='TO' then
   begin
     Timep:=0;
     TradeOn:=1;
     TimeStep:=0;
     Edit1.text:='自動';
     Timer1.Enabled:=true;
   end;

   if S='TOF' then
   begin
     TradeOn:=0;
     TimeStep:=0;
     Edit1.text:='';
   end;

  end
end;

procedure TIndexMain.ontimer(Sender: TObject);
var
  Str1:Pchar;
  p:integer;
begin
  timer1.interval:=20000;
  p:=timesu;
  if p<timeP+1 then exit;

  TimeStep:=0;

  if (TradeOn=1) and (TimeStep=0)  then
  begin
      Timer1.Enabled := False;
      TimeStep:=1;

      if  (TimeStep=1) then
      begin
        TimeStep:=2;
       Making:=TPMaking.Create(Application);
       Making.ShowModal;
       Making.update;
      end;
      Timer1.Enabled := True;
    end;
  timep:=timesu;
end;

function  TIndexMain.Timesu:integer;
Var
  s:string;
  p:integer;
begin
  s:=TimeToStr(time); p:=InStr(1,s,':');
  Timesu:=StrToInt(copy(s,1,p-1)+copy(s,P+1,2));
end;

function TIndexMain.InStr(StartPos:integer;const Str, SubStr:string):integer ;
var
  pStr,p:PChar;
begin
  pStr := PChar(Str);
  p := AnsiStrPos(PChar(pStr+StartPos-1),PChar(SubStr));
  if p = nil then
    result := 0
  else
    result := p-pStr+1;
end;

Form2(Dmaking)です。
procedure TPMaking.OnActivate(Sender: TObject);
var
  n:integer;
begin
  Dmaking;
  PostMessage(Handle,WM_CLOSE,0,0);
end;

procedure TPMaking.Dmaking;
var
  n:integer;
begin
  for n :=1 to 10 do
  begin
    edit1.Text:='Hellow';  application.processMessages;
    sleep(1000);
    edit1.Text:=''; application.processMessages;
    sleep(1000);
  end;
end;

procedure TPMaking.Button2Click(Sender: TObject);
begin
  close;
end;

何か、あまり長いものは載せたらいけないのではと思いますが、
ネット関連のエラーが防げるようになれば、許されるかなと思いまして。

ごめんです。


As  2012-05-25 10:08:12  No: 42239

書き忘れですが、上のはいくつも立ち上がるのを再現するプログラムでした。

EInValidOperation を再現するには、Form2でDmakingをネット接続プログラムに変えて、さらにDmakingを呼び出すのに、Form2でもOntimerを使って呼び出します。
いくつも立ちあがるようになったForm2を使って、OnTimerで呼び出したら、エラーは起きませんでした。

1つしか立ち上がらないForm2を使ってしたら、どうなるか試してみたいですが、はっきり言って大変な作業なので、もういいやという気分です。


Quest  2012-05-25 11:33:59  No: 42240

このソースを自分なりに解釈して、メインのフォーム(IndexMain)のEditに
"TO"と入力してEnterを押すと"自動"という表示に変わり
およそ1秒後にForm2(Dmaking?Pmaking?)が表示され
そのForm2にあるEditに約10秒間"Hellow"が点滅表示されてForm2は閉じる。
その後2回目はタイミングにより20秒から60秒後に表示され
3回目以降は約60秒後(タイミングによっては約40秒後)にForm2が表示され続ける。
という動作になりましたが、これでいいのでしょうか?
多分、1分おきにネット上のどこかに接続したいのでしょうけど
「ネット接続」と一口に言っても、いろいろな処理が考えられます。
取り敢えず、IdHTTPを使ってということなので
Form2にMemoとIdHTTPを追加して
procedure TPMaking.OnActivate(Sender: TObject);
var
  n:integer;
  ms: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  try
    IdHTTP1.Get('http://www.yahoo.co.jp',ms);
    ms.Position := 0;
    memo1.Lines.LoadFromStream(ms);
  finally
    ms.Free;
  end;  Dmaking;
  PostMessage(Handle,WM_CLOSE,0,0);
end;
こんな風にしてみましたが、特にエラーは発生しません。
IdHTTPをどのように使うのか、さらにそれで得られた結果を
どう処理しているのかにポイントだと思います。

発生するエラーからして、どこかでSetFocusを呼んでいませんか?
そこがフォームが閉じられた後に実行されるとか。
デバッグオプションの「言語の例外で通知」にチェックをいれれば
エラーが発生する箇所を特定できるのでは?

あと、老婆心ながら
    Making:=TPMaking.Create(Application);
    Making.ShowModal;
    Making.update;
この部分の最後のupdateってReleaseの間違いでは?
このままだと、作成したTPMakingフォームが開放されずに
どんどんメモリを食っていきます。


Quest  2012-05-25 11:39:19  No: 42241

ありゃ、かぶった。
検証しなおしますが、エラー発生の前に
いくつも立ち上がるのは再現できませんでした。
 Making.update;
これを
 Making.Release;
にしたらどうですか?


Quest  2012-05-25 12:19:03  No: 42242

Dmakingを
procedure TForm2.Ddmaking;
var
  ms: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  try
    IdHTTP1.Get('http://www.yahoo.co.jp',ms);
    ms.Position := 0;
    memo1.Lines.LoadFromStream(ms);
  finally
    ms.Free;
  end;
end;
この様にして
Form2にTimerを追加してそのOnTimerイベントで
procedure TForm2.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;
  Dmaking;
  Sleep(2000); //直ぐに消えてしまうのを防ぐ
  PostMessage(Handle,WM_CLOSE,0,0);
end;
こんな風にしましたけどエラーは出ませんね。
Form2.Timer1のIntervalは1000、EnabledはTrueです。
やはりネット接続自体がエラーの原因ではなく
その結果の処理中に起こるのだと思います。

Form2はどのタイミングでCloseしますか?
また、Form2がいくつも立ち上がるというのはForm2が複数同時に表示されるという意味ですよね。
少なくともアップされたソースでは同時表示されることはないです。
定期的に何度も表示されるのはプログラム通りですが。


KHE00221  2012-05-25 15:46:02  No: 42243

複数表示されるのは
OnActiveでエラーが発生して
PostMessage(Handle,WM_CLOSE,0,0);
が実行されCLOSE されてない気がする

2009 -> XE2 で  Indy のバージョン  がわかって
影響が出てるのかも


As  2012-05-25 21:11:49  No: 42244

Questさん、KHE00221さん、早速にありがとうございます。

ネットに接続するプログラムの中にエラーの原因があるかもというご指摘、研究させてもらいます。
setfocus使ってますし、またupdateの件もありがとうございます。
専門に研究してるわけではないので、意味分からずにupdateを使いまくってます。

Indyの件はその通りだと思います。ネット接続を自動でさせないような意図が感じられます。


As  2012-05-25 23:14:39  No: 42245

やはり、だめでした。

正常に動作している(ネット接続しないで、Hellowを表示する)プログラムTrailにネットに接続するFormのFOnNetを組み込んで、現在はTimerを使っていないFOnNetをTimerを使ってネット接続プログラムPOnNetを作動させるようにしてコンパイルすると、できました。
ボタンを使ってFOnNetを立ち上げると、立ち上がってすぐ消えます。
プログラムミスを訂正して、FOnNetを立ち上げるとTimerですぐにPOnNetを立ち上げるようにすると、コンパイルできずにEInValidOperationエラーが出ました。
関係するすべてのFormのsetfocusを削除しても、このエラーが出ます。

あきらめて、最初からやりますために、すべての修正したFormを保存せずに終了して、projectからも削除して(Hellowを表示する)最初の状態に戻してコンパイルしても、このエラーが出ます。

次に、project名を変えると、このエラーはでなくなり、正常にHellowを表示するようになります。

以上のことからの推論です。
ネットに接続するPOnNetは、delphiに危険なプログラムであると認識されて、それを自動で接続しようとする(Timerを使う)プログラムはコンパイルできないようにされるんだと思います。
そして、それはproject名で記憶され、その名前のprojectは、内容に関係なくコンパイルできないようにされると思います。

ちょっと気になるのが、エラー表示が出たときブレークボタンを押すとプログラムの異常箇所に移動していたと思うんですが、XE2ではどうなんでしょうか。
このエラーのときはどこにも行かないんですけど。


As  2012-05-26 00:23:43  No: 42246

Questさんへ、いろいろ書き込みしていただいているので、まとめて回答します。
1)IndexMainの動きはその通りです。

2)IdHTTP1.Get('http://www.yahoo.co.jp',ms);これだけでいいのですか。エラーなどはでませんか。私のは、サブルーチンを組んですごく複雑なんですけど。2009のときに書き換えたんですが。これが原因かも知れませんね

3)setfocusの件は関係ありませんでした。

4)デバッグオプションの「言語の例外で通知」にチェックをいれれば
エラーが発生する箇所を特定できるのでは?
これは、やり方が分かりません。「表示」に「デバック」があるので、見てみましたが、よくわかりませんでした。

5)updateをreleaseに変えても異常はなおりませんでした。これは、知らないことだったので、すごく感謝しています。

6)Form2はPOnNetの作業が終わってから消してます。Form2がいくつも立ち上がるのは、POnNetが作業している途中に出ることが多いです。最初にまとめて何個も立ち上がることもありますが。

7)やはりネット接続自体がエラーの原因ではなくの件ですが、Questさんのプログラムは「危険」ではないからだと思います。いくらなんでもこれはだめだろうと自分で思えるプログラムで試してみてください。

いろいろとありがとうございました。
時間があればいろいろ試してみたいです。
今後もよろしくお願いします。


Quest  2012-05-26 05:39:39  No: 42247

えーと、いくつかあるのですが、まず
>IdHTTP1.Get('http://www.yahoo.co.jp',ms);これだけでいいのですか
とあるサイトのHTMLを取得するのはこれだけです。
もちろん、このままだと文字コードの問題などあるので後処理も必要ですが。
そもそもAsさんのおっしゃる「ネット接続」というのが具体的に何をするのか分かりませんので
とりあえずインターネットに接続してサーバーにあるデータを取ってくる動作として
このようにしただけです。
これ(IdHTTP1.Getだけ)でいいかどうかは、Asさんのなさりたい事によります。

「言語の例外で通知」はDelphiのメニュー「ツール」から「オプション」を選択し
左側のツリー表示の下のほうにある「デバッガオプション」の「Embarcaderoデバッガ」にある
「言語固有の例外」をクリックしてください。
で、右画面の下のほうに「言語の例外で通知(N)」というチェックボックスがあるので
これにチェックをいれます。
その上でデバッグ実行すれば、エラーが発生したときに停止するので
問題の箇所を特定できると思います。
ただし、try...exceptで処理している例外もすべて停止するので注意が必要です。
でも、コンパイル時にEInvalidOperationエラーが出るって、なんか変な感じがするけど?
ん?
いま読み返したら「エラー表示が出たときブレークボタンを押すと」ってありますね。
って事はすでにチェックを入れているのかな?
で、ブレークボタンでエラーの発生箇所に飛べないということは
ソースが管理下にない所でエラーが発生しているって事ですね。
Indyでエラーが出るなら、プロジェクトオプションの検索パスに
$(BDS)\source\Indy10 を追加すれば表示されるかも。

KHE00221さんのおっしゃる「Indy のバージョンがわかって影響が出てるのかも」っていうのは
動作に必要なパラメータとかが変更になって、うまく動かないんじゃないかということじゃないでしょうか。
「ネット接続を自動でさせない」という表現も、何を持って「自動で接続」なのかよく分かりませんが
URLを指定してGetメソッドを呼べば、ある意味自動でインターネットにアクセスしてくれます。
ノートンやマカフィなどのセキュリティソフトにブロックされる事はありますが
それは通信を許可するように設定すればすみますので。
少なくともIndy自体にファイヤーウォールのような機能は無いと思います。
あと、Delphiにも「これは危険なプログラムだから、コンパイルできなくしてやれ」なんて機能は無いですよ^^;

「危険」なプログラムって何でしょう?(^^ゞ
まさかDoS攻撃するとか、パスワード総当りするとかじゃないですよね。^^;
とあるサイトにいって、そこに表示(またはリンク)されているJPGファイルを根こそぎ自動で
ダウンロードしまくる(ブラウザーで画像に名前を付けて保存の動作を自動で繰り返す)アプリは
Indyで作ったことありますけど、こんなのは「危険」のうちに入らないですし(ですよね?>皆さん^^;)

やはり、これ以上は「ネット接続」とは具体的に何をどうしているのかが分からないと
検証するにも限界がありますね。


As  2012-05-26 05:51:29  No: 42248

Trialで、二つのformにTimerを使って、ネット接続のプログラムを完璧に作動せることに成功しました。

何が原因かは全く分かりませんが。

手順としては、問題のないHellowを表示するProjectのIndexMainのOnTimerを削除してボタンでFOnNetを呼び出すようにしました。呼び出されたFOnNetでPOnNetの呼び出しのにTimerを使ってするようにプログラムしました。
これが完全に作動するすることを確認して、IndexMainにONTimerを組み込みました。

これが成功しました。

後は、本物に組み込めるかどうか試してみます。

Questさん、ネット接続プログラムが悪いのではないようですね。
ありがとうございました。


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

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






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