記事カテゴリ

ユーザー機能


 2024年4月25日(木) 23:54 JST

[Delphi] Excel をアドイン付きで起動する

  • 投稿者:
  • 表示回数
    6,757

通常 Excel を起動して OLE オートメーションとして使用したい場合には、CreateOleObject を使用します。
ただ、この方法ですと個人マクロブック(PERSONAL.XLS)が使えなかったり、アドインが読み込まれていなかったりするなどいろいろ不都合が多いのも事実です。

今回はそんなときに使える 「Excel をふつうに起動させる」方法です。

この方法は、ExcelをCreateProcessで非OLEアプリと同じように起動させて、その後GetActiveOleObjectでOLEを取得します。
Excel を起動するのは、CreateExcelProcess 関数です。ここでは「Excel.Application」という識別子から CLSID を取得し、さらにその CLSID から起動情報を取得した結果を利用してプロセスを作成しています。 また、起動後すぐには OLE のインスタンスを捕まえることができないので、最大 0.5 秒を 10 回計 5 秒を待つ設定にしています。 途中で SetForegroundWindow しているのは XP 上での Excel のバグ対策です。

procedure TForm1.Button1Click(Sender: TObject);

  // Excelプロセス生成
  function CreateExcelProcess(out hProcess: THandle): Bool;

    function GetExcelRegInfo: String;
    const
      KeyFormat = 'CLSID%sLocalServer32';
    var
      Key: String;
    begin
      Key := Format(KeyFormat, [GUIDToString(ProgIDToClassID('Excel.Application'))]);
      Result := GetRegStringValue(Key, '');
    end;

  var
    RegInfo: String;
    PROCESSINFO: TProcessInformation;
    STARTUPINFO: TStartupInfo;
  begin
    Result := false;

    RegInfo := GetExcelRegInfo;
    // Excel が導入されていない場合は、RegInfoが空文字列
    if (RegInfo = '') then exit;

    // 起動情報構造体
    with STARTUPINFO do
    begin
      cb := SizeOf(STARTUPINFO); // 構造体のサイズをセット
      lpReserved := nil;         // 上記以外は初期化
      lpDesktop  := nil;
      lpTitle    := nil;
      dwFlags := 0;
      cbReserved2 := 0;
      lpReserved2 := nil;
      dwysize := 0;
    end;

    // '/e' を付加すると初期のワークブックが抑制できる
    Result := CreateProcess(nil, PChar(RegInfo + ' /e'),
                nil, nil, false, 0, nil, nil, STARTUPINFO, PROCESSINFO);
    hProcess := PROCESSINFO.hProcess;
  end;

const
  RetryCount = 10;
  SErrorRunExcel = 'Excelの起動に失敗しました。';
var
  Excel: OleVariant;
  hProcess: THandle;      // Excel Process Handle
  i: Integer;
begin
  CreateExcelProcess(hProcess);
  try
    Excel := GetActiveOleObject('Excel.Application');
  except
    on E: EOleSysError do
    begin
      // Excelがまだ起動していない場合には、起動をかける
      if (E.ErrorCode = $FFFFFFFF800401E3) then
        if not CreateExcelProcess(hProcess) then
          raise Exception.Create(SErrorRunExcel);

      // Excel再取得
      for i := 0 to RetryCount do
      begin
        sleep(500);
        SetForegroundWindow(Handle);
        try Excel := GetActiveOleObject('Excel.Application') except end;
        if not VarIsEmpty(Excel) then break;
        // ループ最終回で取得できていなかった場合、
        if (RetryCount = i) then raise Exception.Create(SErrorRunExcel);
      end;
    end;
    on E: Exception do exit;
  end;  // Excel起動ループ

  Excel := unassigned;
end;

トラックバック

このエントリのトラックバックURL:
https://www.blackcat.xyz/trackback.php/ProgramingFAQ_del0047

以下のコメントは、その投稿者が所有するものでサイト管理者はコメントに関する責任を負いません。