C#でエクセル起動

エクセルランチャーを作ってみました。

  • 起動元のウィンドウが非アクティブでも、エクセルがフォアグラウンドで起動します。
  • シート名を指定して、起動する事ができます。
  • すでに起動済みのエクセルであれば、アクティブにしてフォアグラウンドにします。
usage: ExcelLauncher.exe <ExcelFilePath> <SheetName>

エクセルのPathと、シート名を指定して起動します。

gitlab

ソースコードはここにあげています。

https://gitlab.com/tyabuta/csharp-excel-launcher

ダウンロード

リリースノートに成果物のexeを添付しておいたので、
使いたい方はダウンロードしてください。

https://gitlab.com/tyabuta/csharp-excel-launcher/tags

以下の設定でビルドしています。

  • .Net 4.5 以上
  • 64bit

エクセル起動させたい

エクセルの起動くらい、
batファイルとかでやろうとしていたんですが、
コンソール 非表示だと、フォアグラウンドに表示されないようで、思い通りに起動できなかった。

start "" sample.xlsx

powershellとか、vbsでCOM使うだけじゃ
毎回、新規起動するとか融通がきかないんですよね。。

$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true
$book  = $excel.Workbooks.Open((Resolve-Path $fileName))
$sheet = $book.Worksheets.Item($sheetName)
$sheet.Activate()

[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($excel) | Out-Null
[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($book)  | Out-Null
[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($sheet) | Out-Null

C#とWin32APIを組み合わせよう

結局柔軟に対応させるには、C#で書いて
win32APIをコールしてやるのが、一番いうことを聞いてくれる気がします。

COMとWin32APIを組み合わせて、納得出来るランチャーを作成しました。

ソース紹介

ソースコードはgitlabにあげているので、見てもらえばよいのですが、
ポイントだけ抜粋して説明しておきます。

動作の流れとしては

  1. 起動中エクセル取得
  2. ブック名を検索して、同名があればアクティブ
  3. なければ新しいブックを作成、アクティブにする、

エクセルの起動

COMを使って起動、COMの解放漏れがないようにしています。

private static void Launch(string filePath, string sheetName)
{
    Microsoft.Office.Interop.Excel.Application excel = null;
    Workbooks books = null;
    Workbook book = null;

    try
    {
        excel = new Microsoft.Office.Interop.Excel.Application();
        ShowExcel(excel);

        books = excel.Workbooks;
        book = books.Open(filePath);

        ActiveSheet(book, sheetName);
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
    }

    if (null != book) Marshal.ReleaseComObject(book);
    if (null != books) Marshal.ReleaseComObject(books);
    if (null != excel) Marshal.ReleaseComObject(excel);
}

起動中のワークブック

既に起動中のワークブックがある場合は、
そちらをアクティブにして表示するようにしています。

// すでに開かれているファイルなら、アクティブにする。
workbook book = getopenedexcelbook(filepath);
if (null != book)
{
    microsoft.office.interop.excel.application excel = null;
    try
    {
        excel = book.application;
        showexcel(excel);
        activesheet(book, sheetname);
    }
    catch (exception e)
    {
        console.writeline(e);
    }

    if (null != book) marshal.releasecomobject(book);
    if (null != excel) marshal.releasecomobject(excel);
    return;
}

ウィンドウの前面化

ウィンドウを全面にもってくるのに、
SetForegroundWindowというAPIがあるんですが、
Vista以降では非推奨になっていて、BringWindowToTopを代わりに使えということみたいですが、
SetWindowPosを使って、一旦最前面に持ってきて解除するという方法が一番簡単なようです。

/**
 * 指定ハンドルのウィンドウを前面に持ってくる。 
 */
public static void ActiveWindowWithSetWindowPos(IntPtr hWnd)
{
    SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
}

おしまい

エクセル起動がイマイチだと感じた人はご利用頂けると幸いです。

COMの操作は解放漏れが発生しやすいので、注意が必要。
タスクマネージャで、終了したはずのEXCELが残っていないかチェックしておくと良いです。

コメントを残す