久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

.NET操作Excel COM對象

 優(yōu)聯(lián)云圖 2014-06-14

多年來 COM 對象一直是 Windows 編程的基礎(chǔ),,然而隨著技術(shù)的進步和發(fā)展,微軟推出了更佳出色的.NET,。.NET Framework 提供了一個稱為公共語言運行庫的運行時環(huán)境(CLR),,它的托管執(zhí)行過程,自動的內(nèi)存管理,,以及在版本的控制上都較COM技術(shù)有很大的提高,。可以預(yù)見的是,,.NET 平臺應(yīng)用程序?qū)⒆罱K取代那些用 COM 開發(fā)的應(yīng)用程序,。但不可避免的是,在向.NET過渡時,,我們還是需要繼續(xù)使用現(xiàn)有的COM對象的,。CLR不管所用的編程語言是什么,所有.NET 應(yīng)用程序都共享一組公共類型,,這些公共類型允許對象互操作,。COM 對象的參數(shù)和返回值使用的數(shù)據(jù)類型有時會與托管代碼中的有所不同。互操作性封送處理是一個打包過程,,在將參數(shù)和返回值移動到 COM 對象或從 COM 對象移出時,,此過程將這些參數(shù)和返回值打包為等價的數(shù)據(jù)類型。

公共語言運行庫通過名為運行庫可調(diào)用包裝 (Runtime Callable Wrapper,,RCW) 的代理來公開 COM 對象,,如圖所示。雖然 RCW .NET 客戶端看來是普通的對象,,但它的主要功能是封送在 .NET 客戶端和 COM 對象之間傳遞的調(diào)用,。同時.NET提供Interop 程序集,它用作托管和非托管代碼之間的橋梁,,將 COM 對象成員映射為等價的 .NET 托管成員,。

 

 

l       .NET中如何引用COM組件?

 

方法一,,通過IDE來生成PIA:

    首先,,工程添加引用,選擇COM選項卡,,選擇Excel Object Library xx.0(xx為版本號,,不同版本的Office,,生成的PIA的版本也不同)。如下圖所示:

 

 

這個引用過程就是RCW的打包過程,,.NET自動創(chuàng)建 PIA,。當然,你也可以通過.NET提供的工具Tlbimp.exe手動創(chuàng)建PIA,。

 

方法二,,手動生成PIA

    首先,啟動.NET Framework 2003工具中的控制臺:

 

 

然后找到當前操作系統(tǒng) 中安裝的EXCEL.EXE的位置,,輸 入:

 

 

結(jié)果就會在指定目錄里生成Excel.dll,。當然,你還可以指定生成PIA的命名空間名稱和程序集名,。

 

 

生成之后的dll是經(jīng)過包裝后的.NET的程序集,,可以直接引用。(很明顯,,是使用IDE來得方便,,但有當要使用一個未在Windows上注冊的COM組件時,就要使用到這個手動工具),。

    引用之后就可以通過IDEObject Browser來查看COM組件里提供的對象和方法了:

 

 

 

當然,,由于語法的不同,.NET上不同語言封裝之后的COM對象也稍稍有點不同,,比如C#VB.NET,。上圖是C#工程里的Object Browser

    另外,,在ASP.NET應(yīng)用開發(fā)中使用Excel COM組件還需要對該組件進行訪問授權(quán),,因為ASP.NET程序的用戶為ASPNET,而該用戶在默認情況下是無權(quán)訪問COM對象的,。可以使用命令行命令dcomcnfg來對COM對象授權(quán),。

 

 

l       Excel對象結(jié)構(gòu)Microsoft Excel object hierarchy

    當啟動Excel應(yīng)用程序的時候,,將會啟動一個Excel Application進程(進程名為:EXCEL.EXE),一個Excel文件相當于Excel Application中的一個Workbook對象,。文件中的一個Sheet相當于Excel Workbook對象中的Worksheet對象,,而Excel單元格,行,,列,,區(qū)域都是一個Range對象。Excel里的主要對象就是Workbook, Worksheet, Range,。具體的類結(jié)構(gòu)如下圖:


你可以通過錄制Excel Macro來了解操作Excel的方法,,比如:賦值,,格式化等操作。如下圖:

 

 

 

然后按Alt+F11進入VBA編輯環(huán)境,,查看代碼,。在.NET中利用Excel COM組件操作Excel 其方法和屬性都跟VBA中的代碼類似,如果是VB.NET有些VBA的代碼甚至可以直接拷貝過來使用,。

 

 

l       創(chuàng)建Excel對象


以下代碼演示了怎么在.NET下新建一個Workbook,,添加一個Worksheet,并對其中的單元格賦值,,最后保存在當前程序運行目錄下:

[C#]

using Excel;

_Application xlApp = null;

            _Workbook xlWorkbook = null;

            _Worksheet xlWorksheet = null;

 

            System.Reflection.Missing oMissing = System.Reflection.Missing.Value;

            string saveAsPath = "";

 

            try

            {

                xlApp = new ApplicationClass();

                xlApp.Visible = true;

                xlWorkbook = xlApp.Workbooks.Add(oMissing);

                xlWorksheet = xlWorkbook.Worksheets.Add(oMissing, oMissing, 1, oMissing) as _Worksheet;

                xlWorksheet.Name = "NewWorksheet";

                xlWorksheet.Cells[1, 1] = "Topic: ";

                xlWorksheet.Cells[1, 2] = ".Net Interop Excel Demo";

                saveAsPath = System.Windows.Forms.Application.StartupPath + "http://" + xlWorkbook.Name;

                xlWorkbook.SaveAs(saveAsPath, oMissing, oMissing, oMissing, oMissing,

                    oMissing, Excel.XlSaveAsAccessMode.xlShared, oMissing, oMissing, oMissing,

                    oMissing, oMissing);

                xlApp.Quit();

            }

            catch(Exception ex)

            {

                MessageBox.Show(ex.Message);

            }

            finally

            {

                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

          xlApp = null;

                GC.Collect();

      }

在上面的代碼中,,你可能會注意到出現(xiàn)了許多oMissing對象:

            System.Reflection.Missing oMissing = System.Reflection.Missing.Value;

這是因為有些方法(比如:SaveAs方法)的參數(shù)是可選的,因為使用的是 C#C#沒有VB/VB.NET中的可選參數(shù)),,必須發(fā)送一個值表明缺少值,。大家可能會認為可以簡單地傳遞null,但是方法要求使用引用傳遞參數(shù)(VB/VB.NET中的ByRef,,這些方法最初是由VB實現(xiàn)的),,因此無法使用null表示缺省值,而使用了System.Reflection.Missing.Value,。

 

[VB.NET]

Imports Excel

 Dim xlApp As Excel.Application

        Dim xlWorkbook As Workbook

        Dim xlWorksheet As Worksheet

        Dim saveAsPath As String = ""

        Try

            xlApp = New Excel.Application

            xlApp.Visible = True

            xlWorkbook = xlApp.Workbooks.Add()

            xlWorksheet = xlWorkbook.Worksheets.Add()

            xlWorksheet.Name = "NewWorksheet"

            xlWorksheet.Cells(1, 1) = "Topic: "

            xlWorksheet.Cells(1, 2) = ".NET Interop Excel Demo"

            saveAsPath = System.Windows.Forms.Application.StartupPath + "/" + xlWorkbook.Name

            xlWorkbook.SaveAs(saveAsPath)

            xlApp.Quit()

        Catch ex As Exception

            MessageBox.Show(ex.Message)

        Finally

            If Not xlApp Is Nothing Then

                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)

                xlApp = Nothing

                GC.Collect()

            End If

  End Try

通過比較,,可以看到對于Excel PIA的調(diào)用上,還是VB.NET要占便宜, 畢竟是VB/VB.NET一家親,。另外一點,,上面的代碼在最后都調(diào)用了

                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)

因為COM對象是非托管對象,雖然當RCW已經(jīng)不在程序范圍之內(nèi),,并且不能再被程序訪問,,但是RCW沒被垃圾回收器回收并銷毀,那么它就沒有真正釋放被其包裝的COM對象,,所以內(nèi)存的釋放也必須另做處理,。另外需要注意的是使用Excel Object Library COM對象不同的Office版本包裝出來的PIA中的方法會有不同,尤其在使用C#進行編程的時候需要注意參數(shù)個數(shù)在不同版本下的變化,。所以最好使用低版本的PIA以保證程序在安裝了不同版本的機器上都能運行,。

    通過比較也可以發(fā)現(xiàn),因為VB.NET的可選參數(shù)的語法,,在操作Excel上,,VB.NET的代碼要比C#的代碼更加的簡潔。

 

l       幾種Excel賦值方法的比較


    通常在實際項目的開發(fā)中,,對Excel的操作往往是很復雜的,,除了復雜的格式化要求,還有大量的賦值操作,。通常是從數(shù)據(jù)庫里取出大量的數(shù)據(jù)在程序中處理之后再賦值給Excel的單元格里,,大量的,、連續(xù)的單元格賦值操作在數(shù)據(jù)量大的時候會明顯的降低程序的效率。這里提出幾種大量Excel單元格賦值的方法,,供大家參考,。

假設(shè)要將數(shù)據(jù)庫里的以下數(shù)據(jù)導出到Excel中:

No

Name

Title

Department

Telephone

E-Mail

1

Jossef Goldberg

President & CEO

Office of the President

555-0100

[email protected]

2

Ashley Larsen

Senior VP Sales & Mktg

Sales

555-0109

[email protected]

3

Eric Lang

Corporate Counsel

Operations

555-0110

[email protected]

4

Linda Leste

Treasurer

Finance

555-0111

[email protected]

5

Ketan Dalal

Secretary

Finance

555-0112

[email protected]

在本示例中,以“A1”作為開始單元格,。

Delegate Sub SetValueToExcel(ByVal xlWorksheet As Worksheet, ByVal strBeginCell As String, ByVal objDataTable As System.Data.DataTable)

 

' SetValueToExcelCellByCell button click

Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click

        Me.MakeExcel("SetValueToExcelCellByCell.xls", AddressOf SetValueToExcelCellByCell)

End Sub

 

' SetValueToExcelByClipboard button click

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

        Me.MakeExcel("SetValueToExcelByClipboard.xls", AddressOf SetValueToExcelByClipboard)

End Sub

 

' SetValueToExcelByResize button click

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        Me.MakeExcel("SetValueToExcelByResize.xls", AddressOf SetValueToExcelByResize)

End Sub

 

Private Sub MakeExcel(ByVal strExcelName As String, ByVal subSetValueToExcel As SetValueToExcel)

        Dim xlApp As Excel.Application

        Dim xlWorkbook As Workbook

        Dim xlWorksheet As Worksheet

        Dim saveAsPath As String = ""

        Try

            xlApp = New Excel.Application

            xlApp.Visible = True

            xlWorkbook = xlApp.Workbooks.Add()

            xlWorksheet = xlWorkbook.Worksheets.Add()

      xlWorksheet.Name = strExcelName.Replace(".xls", "")

            ' Call Delegate

            subSetValueToExcel(xlWorksheet, "A1", Me.objDataTable)

            Me.FormatTable(xlWorksheet, "A1", Me.objDataTable)

            saveAsPath = System.Windows.Forms.Application.StartupPath + "/" + strExcelName

            xlApp.DisplayAlerts = False

            xlWorkbook.SaveAs(saveAsPath)

            xlApp.DisplayAlerts = True

            xlApp.Quit()

        Catch ex As Exception

            MessageBox.Show(ex.Message)

        Finally

            If Not xlApp Is Nothing Then

                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)

                xlApp = Nothing

                GC.Collect()

     End If

  End Try

End Sub

 

1. 利用Offset屬性對Excel單元格賦值,。

Excel Object Library Range對象中提供了一個屬性叫Offset,顧名思義就是根據(jù)該Range進行偏移,,并返回偏移之后的Range對象:

Public Overridable ReadOnly Property Offset(Optional ByVal RowOffset As Object = Nothing, Optional ByVal ColumnOffset As Object = Nothing) As Excel.Range

利用這一屬性,,我們就可以在已知開始單元格的基礎(chǔ)上進行偏移并賦值,而不用同時定位行和列的絕對位置:

Private Sub SetValueToExcelCellByCell(ByVal xlWorksheet As Worksheet, ByVal strBeginCell As String, ByVal objDataTable As System.Data.DataTable)

  ' Output the title

        For i As Integer = 0 To objDataTable.Columns.Count - 1

            xlWorksheet.Range(strBeginCell).Offset(0, i).Value = objDataTable.Columns(i).ColumnName

        Next

 

        ' Output the value

        For i As Integer = 0 To objDataTable.Rows.Count - 1

            For j As Integer = 0 To objDataTable.Columns.Count - 1

                xlWorksheet.Range(strBeginCell).Offset(1 + i, j).Value = objDataTable.Rows(i)(j).ToString().Trim()

            Next

        Next

End Sub

代碼中,,第一個循環(huán)輸出表頭(列名),,因為表頭只占一行,所以行偏移量是0,;第二個循環(huán)輸出DataTable里的數(shù)據(jù),,因為表頭占去第一行,所以行偏移量從1開始,。

此方法相當于遍歷了所有要賦值的單元格,,一一進行賦值操作。也就是說當數(shù)據(jù)量為m*n的情況下,,xlWorksheet.Range(strBeginCell).Offset(1 + i, j).Value被執(zhí)行了m*n次,,跨越托管堆到非托管堆的數(shù)據(jù)轉(zhuǎn)移發(fā)生了m*n次。同時考慮到RCWCOM對象中方法的參數(shù)都包裝成Object,,因此這里還要發(fā)生大量的裝箱操作,,所以當數(shù)據(jù)量非常大的時候,該方法的速度是比較慢的,。

2. 利用系統(tǒng)剪切板進行的賦值操作

這種方法是基于Excel格式的原理而考慮的,,比如:將notepad中的以Tab分隔的數(shù)據(jù)拷貝粘貼到Excel中,你會發(fā)現(xiàn)原來Excel中的列與列是之間Tab符隔開,,行與行之間是回車換行隔開的,。

 

 

 

利用這種格式,我們可以想到,,先將DataTable里的數(shù)據(jù)轉(zhuǎn)化成Tab分隔的數(shù)據(jù),再放到系統(tǒng)剪切板中,,最后粘貼到Excel上就完成上面的賦值操作了,。

Private Sub SetValueToExcelByClipboard(ByVal xlWorksheet As Worksheet, ByVal strBeginCell As String, ByVal objDataTable As System.Data.DataTable)

        Dim objSB As System.Text.StringBuilder = New System.Text.StringBuilder

 

        ' Build the title

        For i As Integer = 0 To objDataTable.Columns.Count - 1

            objSB.Append(objDataTable.Columns(i).ColumnName)

            If i < objDataTable.Columns.Count - 1 Then

                objSB.Append(vbTab)

            End If

        Next

        objSB.Append(vbCrLf)

 

        ' Build the value

        For i As Integer = 0 To objDataTable.Rows.Count - 1

            For j As Integer = 0 To objDataTable.Columns.Count - 1

                objSB.Append(objDataTable.Rows(i)(j).ToString().Trim())

                If j < objDataTable.Columns.Count - 1 Then

                    objSB.Append(vbTab)

                End If

            Next

            If i < objDataTable.Rows.Count - 1 Then

                objSB.Append(vbCrLf)

            End If

        Next

 

        System.Windows.Forms.Clipboard.SetDataObject(objSB.ToString())

        xlWorksheet.Range(strBeginCell).Activate()

        xlWorksheet.Paste()

  System.Windows.Forms.Clipboard.SetDataObject("")

 

End Sub

    這里的主要操作主要是在組裝StringBuilder上,而系統(tǒng)剪切板利用DDE(Dynamic Data Exchange)的方式轉(zhuǎn)移數(shù)據(jù),,速度還是很快的,。但是,,因為系統(tǒng)剪切板是系統(tǒng)共享資源,所以在多線程的應(yīng)用程序里需要考慮對該共享資源的同步問題,。另外,,在Web應(yīng)用中,因為用戶是ASPNET而不是Administrator所以對Clipboard的訪問是沒有權(quán)限的,。因此該方法也是受限的,。

3. 利用數(shù)組進行賦值操作

因為Range.Value可以接受數(shù)組,并將數(shù)組里的值賦給Range內(nèi)相應(yīng)單元格,。利用這個特點,,我們可以將Range設(shè)定為整個要賦值的范圍,再將DataTable里的數(shù)據(jù)放到一個Object二維數(shù)組中,,讓COM對象自己完成對范圍賦值的過程,。

Private Sub SetValueToExcelByResize(ByVal xlWorksheet As Worksheet, ByVal strBeginCell As String, ByVal objDataTable As System.Data.DataTable)

 

        ' The first row is title.

        Dim objData(objDataTable.Rows.Count, objDataTable.Columns.Count - 1) As Object

 

        ' Set the title

        For i As Integer = 0 To objDataTable.Columns.Count - 1

            objData(0, i) = objDataTable.Columns(i).ColumnName

        Next

 

        ' Set the value

        For i As Integer = 0 To objDataTable.Rows.Count - 1

            For j As Integer = 0 To objDataTable.Columns.Count - 1

                objData(1 + i, j) = objDataTable.Rows(i)(j).ToString().Trim()

            Next

        Next

 

        xlWorksheet.Range(strBeginCell).Resize(objData.GetUpperBound(0) + 1, objData.GetUpperBound(1) + 1).Value = objData

End Sub

 

這里用到Range.Resize屬性,這個屬性將已知開始的單元格擴大為要賦值的區(qū)域,。

Public Overridable ReadOnly Property Resize(Optional ByVal RowSize As Object = Nothing, Optional ByVal ColumnSize As Object = Nothing) As Excel.Range

注意:RowSize, ColumnSize必須大于1

這個賦值過程,,跨越托管堆到非托管堆的數(shù)據(jù)轉(zhuǎn)移只有一次,而且沒有大量的裝箱操作,,也不用考慮到系統(tǒng)共享資源的問題,,所以在大數(shù)據(jù)量賦值的時候,應(yīng)該考慮使用該方法,。

 

 

最后生成Excel

 

l       調(diào)用Excel

說到Excel就不能不提到宏,,正是因為能夠使用VBAExcel進行二次開發(fā)使得Excel成為最好的電子表格工具,這也使得通過.NET操作Excel又多出一種渠道,,我們可以利用Excel中的VBA進行我們的快速開發(fā),。比如:利用宏將Excel轉(zhuǎn)化為PDF格式的文件。

先來看看Excel.Application.Run方法,,Run方法共有30個參數(shù),,第一個是要調(diào)用宏方法的限定名,剩下的是方法的參數(shù),。使用該方法可以調(diào)用Application中的宏,,宏可以寫在.xls或者.xla文件中,通過宏方法限定名來調(diào)用,,宏方法的限定名為:

“文件名!模塊名.方法名”(如:PdfConverter.xla!MdlMain.ConvertToPDF

Private Sub ConvertToPDF(ByVal xlApp As Application, ByVal strExcelName As String, ByVal strSheetName As String)

        Dim strMacroFileName As String = System.Windows.Forms.Application.StartupPath + "/PdfConverter.xla"

        Dim strMacroMethodName As String = "PdfConverter.xla!MdlMain.ConvertToPDF"

        Dim strPDFFileName As String = xlApp.Workbooks(strExcelName).Path + "/" + strExcelName.Replace(".xls", "") + ".pdf"

        xlApp.DisplayAlerts = False

        xlApp.Workbooks.Open(strMacroFileName)

        xlApp.Run(strMacroMethodName, strExcelName, strSheetName, strPDFFileName)

        xlApp.DisplayAlerts = True

End Sub

寫在PdfConverter.xla中的VBA代碼:

Public Sub ConvertToPDF(ByVal strExcelName As String, ByVal strSheetName As String, ByVal strPDFFileName As String)

 

        ' Define the postscript and .pdf file names.

        Dim strPSFileName As String

 

        Dim xlWorksheet As Worksheet

        Dim objPdfDistiller As PdfDistiller

 

        strPSFileName = Left(strPDFFileName, InStrRev(strPDFFileName, "/")) & "tmpPostScript.ps"

        Application.ActivePrinter = "Adobe PDF on Ne02:"

 

        ' Print the Excel ActiveSheet to the postscript file

        xlWorksheet = Application.Workbooks(strExcelName).Worksheets(strSheetName)

        xlWorksheet.PrintOut(Copies:=1, preview:=False, ActivePrinter:="Acrobat Distiller", printtofile:=True, Collate:=True, prtofilename:=strPSFileName)

 

        ' Convert the postscript file to .pdf

        objPdfDistiller = New PdfDistiller

        objPdfDistiller.FileToPDF(strPSFileName, strPDFFileName, "")

 

        ' Finally, delete the postscript file

  Call Kill(strPSFileName)

 

End Sub

調(diào)用之后生成PDF文件:

 

 

   比如操作Excel,,我們最直接的方法就是利用Excel提供的Excel Object Library COM組件,并將包裝后的程序集叫做“互操作程序集” (Primary Interop Assembly, PIA),。

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導購買等信息,,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多