通常 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;

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