0

次のコードを使用して、データ テーブルを Excel に保存できる ASP.net フォームで Excel ファイルに動的に書き込みます。

//Create Excel Object
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook workbook = excel.Workbooks.Open(target);
Microsoft.Office.Interop.Excel.Worksheet worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Worksheets[1];

worksheet.Name = "Worksheet1";
excel.Visible = false;
//Generate Fields Name
foreach (DataColumn col in dataTable.Columns)
{
    colIndex++;
    excel.Cells[1, colIndex] = col.ColumnName;
}
object[,] objData = new object[rowNo, columnNo];
for (int row = 0; row < rowNo; row++)
{
    for (int col = 0; col < columnNo; col++)
    {
        objData[row, col] = dataTable.Rows[row][col];
    }
}
Microsoft.Office.Interop.Excel.Range range;
range = worksheet.Range[excel.Cells[2, 1], excel.Cells[rowNo + 1, columnNo]];
range.Value2 = objData;
worksheet.Columns.AutoFit();

workbook.Save();
workbook.Close();

IntPtr hwnd = new IntPtr(excel.Hwnd);
IntPtr processId;
IntPtr foo = GetWindowThreadProcessId(hwnd, out processId);
Process proc = Process.GetProcessById(processId.ToInt32());
proc.Kill();

//excel.Quit();
GC.Collect();
GC.WaitForPendingFinalizers();

データはExcelファイルに正常に書き込まれます。ただし、上記のように proc.Kill() を使用してプロセスを強制終了しようとすると、次の例外が発生します

説明: 現在の Web 要求の実行中に未処理の例外が発生しました。エラーの詳細とコード内のどこでエラーが発生したかについては、スタック トレースを確認してください。

例外の詳細: System.ComponentModel.Win32Exception: アクセスが拒否されました

ソース エラー:

現在の Web 要求の実行中に未処理の例外が生成されました。例外の発生元と場所に関する情報は、以下の例外スタック トレースを使用して特定できます。

スタックトレース:

[Win32Exception (0x80004005): Access is denied]
   System.Diagnostics.Process.GetProcessHandle(Int32 access, Boolean throwIfExited) +1985316
   System.Diagnostics.Process.Kill() +49
   Faculty_Report1.FetchData_EXCEL(String prog, String cls, String spcln, String fromdate, String todate) +2413
   Faculty_Report1.fetchselectedvalues_EXCEL() +1044
   System.Web.UI.WebControls.ImageButton.OnClick(ImageClickEventArgs e) +187
   System.Web.UI.WebControls.ImageButton.RaisePostBackEvent(String eventArgument) +165
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3707

proc.Kill() メソッドを使用する代わりに、excel.Quit() メソッドを使用してみましたが、プロセスが終了しません。これを行うと、ユーザーがレポートを生成しようとするたびに、新しい Excel プロセスが作成されます。

web.config ファイルにユーザーの偽装がありますが、何も変わりません。

  <system.web>
    <identity impersonate="true" userName="xxxxxx" password="xxxxxxxx" />
  </system.web>

例外を回避し、Excel プロセスが正常に終了することを確認する方法についての指針はありますか? ここで見つけた COM クリーンアップ ソリューションを試しましたが、うまくいきません。

4

3 に答える 3

5

サーバー (ASP.NET など) での相互運用の使用は、MS ではサポートされていません。http://support.microsoft.com/default.aspx?scid=kb;EN-US;q257757# kb2を参照

Windows Vista MS 以来、Windows サービスが「デスクトップのような」ことを行うのを防ぐいくつかのセキュリティ関連の対策が導入されています...つまり、機能させるにはいくつかのセキュリティ対策を回避する必要があります (お勧めしません!)。

サーバー シナリオで Excel を処理するには、いくつかのオプション (無料および商用) があります。

私はAspose.CellsFlexcelをお勧めします ... SpreadsheetGearは試しませんでしたが、多くの良い点を聞いて読んで...

無料のオプション (ただし、新しい xlsx 形式のみ!) は、たとえば 、MSおよびEPPlusの OpenXML 2 です。

于 2012-06-20T15:46:23.037 に答える
1

単純な Excel データ テーブルを作成するには、interop 以外に興味深いオプションがいくつかありますが、interop を使用する必要がある場合に Excel で役立つ方法がいくつかあります。

最初のことが最初です。既存のアプリケーションを再利用できることが確実な場合は、'oldschool' getactiveobject を使用して既存のインスタンスを取得できます。

    using System.Runtime.InteropServices;

    Microsoft.Office.Interop.Excel.Application excel;
            try
            {
                excel = (Microsoft.Office.Interop.Excel)Marshal.GetActiveObject("Excel.Application");
            }
            catch
            {
                 excel = new Microsoft.Office.Interop.Excel.Application();
            }

Excel アプリケーションを正常に終了するには、すべてのハンドルを破棄する必要がありますが、それが COM クリーンアップの意味だと思いますか? すべてのハンドルが marshal.releasecomobject で解放されていることを確認するのは面倒な場合があります (おそらく、現代の相互運用では不要になったのでしょうか?)。そのため、ワークシート、ワークブック、範囲などのすべてのオフィス相互運用の「ハンドル」をラッパー。私が持っているコードはあまり用途が分かれていませんが、一般的なアイデアを得るためにここに投稿します。

public class WrapperBase<T>: IWrapper
{

    protected T obj;
    protected internal WrapperBase(IWrapper Owner)
    {
        SetOwner(Owner);
    }

    protected WrapperBase() { }


    CultureSwitcher cultswitch;
    public CultureSwitcher CultureSwitcher
    {
        get
        {
            if (cultswitch == null)
            {
                if (owner != null) return owner.CultureSwitcher;
                cultswitch = new CultureSwitcher();
            }
            return cultswitch;
        }
    }

    public T Object { get { return obj; } internal set { obj = value; } }


    //public abstract void Save();

    public bool IsDisposed { get { return disposed; } }

    bool disposed;
    public void Dispose()
    {
        Dispose(false);
    }

    void Dispose(bool fromfinalize)
    {
        if (disposed) return;
        disposed = true;
        if (!fromfinalize)
            GC.SuppressFinalize(this);

        CultureSwitcher.Try(OnDisposing);

        if (obj != null)
        {
            while (Marshal.ReleaseComObject(obj) > 0) { }
            obj = default(T);
        }

        if (cultswitch != null)
        {
            cultswitch.Dispose();
            cultswitch = null;
        }

        SetOwner(null);
    }

    protected virtual void OnDisposing()
    {
        if (children != null)
        {
            foreach (var c in children)
                c.Dispose();
            children = null;
        }
    }

    ~WrapperBase()
    {
        Dispose(true);
    }

    List<IWrapper> children;
    IWrapper owner;

    public IWrapper Owner
    {
        get { return owner; }
    }

    protected void SetOwner(IWrapper Owner)
    {
        if (Owner == owner) return;
        if (owner != null)
        {
            owner.DeRegister(this);
        }
        owner = Owner;
        if (owner != null)
        {
            owner.Register(this);
        }
    }

    public void Register(IWrapper Child)
    {
        if (disposed)
            throw new ObjectDisposedException("Cannot register children after disposing");
        if (children == null)
            children = new List<IWrapper>();
        children.Add(Child);
    }

    public void DeRegister(IWrapper Child)
    {
        if (disposed) return;
        children.Remove(Child);
    }

    protected IEnumerable<IWrapper> GetChildren()
    {
        return children;
    }
}
于 2012-06-20T15:55:16.463 に答える
0

また、過去に相互運用機能を使用して Excel アプリケーションを完全に閉じることができないという問題がありましたが、解決策はアプリケーションのインスタンスを解放することであることがわかりました。次のことを試してください。

excel.Quit();
excel = null;

単純すぎるように思えますが、Excel のゴースト インスタンスがアプリケーションの OS に残るのを防ぐことができました。

于 2012-06-20T15:50:06.007 に答える