CreateOleObject で EXCEL を開いた後プロセスが残ってしまう

解決


螺子まき  2017-02-08 10:52:48  No: 48530  IP: 192.*.*.*

はじめまして

EXCELをCreateOleObject で開いた後開放してもダミープロセス?が残ってしまう現象に悩んでいます。
下記に再現コードを載せます。
このままだとプロセスは残りません(タスクマネージャを開いて観察しています)
しかし、★1,2のコメントをはずすとプロセスが残ったままになります。(プログラムを終了すると消えます)
★のコードは高速にアクセスする常套手段のようです。■のコードでアクセスするより2桁ほど早いです。
想像しますに、variantの開放がうまくできていないのではないかとおもいますが回避手段がわかりません。
どうか宜しくお願いします。

procedure TForm1.Button1Click(Sender: TObject);

var
  Excel: OleVariant;
  excelApp, ExcelBook, workSheet: OleVariant;
  vrange: Variant;
  MaxRow: Integer;
  Ctmp: Variant;
begin
  Excel := CreateOleObject('EXCEL.Application');

  try
    excelApp := Excel.application;

    ExcelBook := excelApp.WorkBooks.Open('C:\temp\test.xlsx', False);
    workSheet := ExcelBook.WorkSheets[1];
    // vrange := workSheet.Range[workSheet.cells[1, 1], workSheet.cells[10, 10]].value;  //★2
    Ctmp := workSheet.Cells[1, 1].value; //■
    Memo1.Lines.Add(vartoStr(Ctmp));
    sleep(500);

  finally

    excelApp.Quit;
    Excel := Unassigned;

    excelApp := Unassigned;
    ExcelBook := Unassigned;
    workSheet := Unassigned;
    // vrange := Unassigned;    //★1

  end;

end;

編集 削除
螺子  2017-02-08 10:55:04  No: 48531  IP: 192.*.*.*

すみません。環境依存は少ないと思いますが、試しているのはDelphi10.1、Windows7 または WindowsServer2012R2Std です。

編集 削除
igy  2017-02-08 13:12:43  No: 48532  IP: 192.*.*.*

関係ないかもしれませんが、

Excel := CreateOleObject('EXCEL.Application'); 
の後に、
Excel.Visible := True;
を、

finallyの前に、
ExcelBook.Close(SaveChanges:=False);

置いてみた場合でも、結果は同じですか?

編集 削除
螺子まき  2017-02-08 15:20:27  No: 48533  IP: 192.*.*.*

回答ありがとうございます。

試してみましたが、EXCELプロセスは相変わらず残ったままです。

なお、上記コードを試すには
uses ComObj;
が必要ですね。申し訳ありません。

vrange は  variant配列なのに適当な開放をしているせいでしょうか?

編集 削除
螺子まき  2017-02-08 15:22:24  No: 48534  IP: 192.*.*.*

全体を 無名メソッドでスレッド化すればいいんじゃないか?(適当)
と思いトライしてみましたが、無名メソッドスレッドの中では
CreateOleObject('EXCEL.Application'); 
が失敗します ^ ^;

編集 削除
au  2017-02-08 15:54:12  No: 48535  IP: 192.*.*.*

workSheet.cells[1, 1],workSheet.cells[10, 10]で取得してるオブジェクトが解放されてないんじゃないかと。

変数で受けてあげれば終了しませんか?
それか、formatかなんかで文字列でセル範囲を指定するようにするか

編集 削除
螺子まき  2017-02-08 15:56:23  No: 48536  IP: 192.*.*.*

auさん、まさに私もそれを想像したのですが、
vrange :=unassinged;  も
finalize(vrange);も
効果なしでした。

是非開放の仕方を教えてください!!!

編集 削除
au  2017-02-08 16:38:40  No: 48537  IP: 192.*.*.*

いや、workSheet.Rangeで返ってくるオブジェクトだけでなく、Rangeの引数に渡してるCellsの方のオブジェクトもです。

こっちで実験してみた感じだとそれでExcel終了しました

編集 削除
螺子まき  2017-02-08 17:25:40  No: 48538  IP: 192.*.*.*

auさんありがとうございます

いろいろ試してみました。プロセスを消すことはできましたが変わりにどうしてもセーブダイアログが出ます。( readOnly で開いているのに!)

・・・どうかご教示願います。


procedure TForm1.Button1Click(Sender: TObject);

var
  excelApp, ExcelBook, workSheet: OleVariant;
  vrange: Variant;

begin

  try
    excelApp := GetActiveOleObject('Excel.Application');
  except
    excelApp := CreateOleObject('Excel.Application');
  end;

  try

    ExcelBook := excelApp.WorkBooks.Open(Filename := 'C:\temp\test.xlsx',  readOnly := True);
    //radonly なのになぜかセーブダイアログが出る!!
    workSheet := ExcelBook.WorkSheets[1];
    vrange := workSheet.Range[workSheet.cells[1, 1], workSheet.cells[10, 10]].value; // ★2

    sleep(500);

  finally

    //  この2行必須?
    workSheet.cells[1, 1] := Unassigned;  
    workSheet.cells[10, 10] := Unassigned;

    workSheet := Unassigned;

    ExcelBook := Unassigned;
    vrange := Unassigned; // ★1

    //下記2行どちらかがあるとセーブダイアログは出ないがプロセス残る
    // excelApp.DisplayAlerts := False;
    // excelApp.ActiveWorkBook.Saved:= 1;

    excelApp.Quit;
    excelApp := Unassigned;

  end;

end;

編集 削除
igy  2017-02-08 18:01:41  No: 48539  IP: 192.*.*.*

> どうしてもセーブダイアログが出ます。



>ExcelBook := Unassigned;
の前に、
ExcelBook.Close(SaveChanges:=False); 
を 
置いてみた場合、どうなりますか?

編集 削除
au  2017-02-08 18:10:25  No: 48540  IP: 192.*.*.*

var
  Cell1, Cell2: OleVariant;

  略
  Cell1 := workSheet.cells[1, 1];
  Cell2 := workSheet.cells[10, 10];
  vrange := workSheet.Range[Cell1, Cell2].value; 

  Cell1 := Unassigned;
  Cell2 := Unassigned;

とかだとどうでしょう

編集 削除
Mr.XRAY  2017-02-08 18:28:35  No: 48541  IP: 192.*.*.*

ちょっとやってみました.
質問された方が提示したコードを実行してみました.
全て Windows 7 U64(SP1) + Excel 2010 の結果です.

Delphi XE(UP1) Por --> プロセス EXCEL.EXE は残りません
Delphi 10.1 Berlin Starter --> プロセス EXCEL.EXE が残りました.

au さんのように Range オブジェクトを分けたら,
どちらの Delphi で作成した EXE でもプロセスは残りませんてした.
Unassigned を実行しなくてもプロセスが残ることはありませんでした.

編集 削除
螺子まき  2017-02-09 16:32:54  No: 48542  IP: 192.*.*.*

igy さん、Mr.XRAY さん、au さん
ありがとうございます。

キモは、

    C1 := workSheet.cells[1, 1];
    C2 := workSheet.cells[10, 10];
    vrange := workSheet.Range[C1,C2].value; 

    C1 := Unassigned;
    C2 := Unassigned;

ということですね。。。やっとEXCELプロセスが消えてくれました。
重ねて御礼申し上げます。

編集 削除