2012年9月17日

使用 COM 方式實現 Excel 資料匯入匯出的功能

對使用者來說,在 Excel 整理大量的資料還是比較方便又快速的,
傳統 TIPTOP 的匯入 Excel 資料的方式都是需要先轉為文字檔,
利用分隔符號來區分資料的欄位,但是這樣已是古代的作業方式了。

通常應用程式開發工具可以使用 COM 的方式是跟 Excel Application 進行通訊,
GDC 是 Clinet 端的軟體,所以可以使用 COM 的方式來讀取 Excel 的資料,
參考 4js 提供的 Genero 使用說明,找到 ui,interface.frontcall() 的使用方式。

建立 COM
1:CALL ui.interface.frontcall("WinCOM","CreateInstance",[program],[handle]
  A. program - 系統中註冊的 COM 名稱
  B. handle - 回傳狀態 -1 表示有錯誤,此值在 API 可以使用

使用指定的方法
2:CALL ui.interface.frontcall("WinCOM","CallMethod",[handle,method,arg1,...],[result])
  A.handle - 使用宣告的 handle 值。
  B. method - 函數的名稱。
  C. arg1 - 傳送給方法用的參數
  D. result - 回傳狀態 -1 表示有錯誤,0 表示沒有錯誤

讀取屬性值
3.CALL ui.interface.frontcall("WinCOM","GetProperty",[Handle,member],[result]
  A. handle - 使用宣告的 handle 值
  B. member - 取得屬性的
  C. result - 回傳狀態 -1 表示有錯誤,0 表示沒有錯誤

設定屬性值
4.CALL ui.interface.frontcall("WinCOM","SetProperty",[handle,member,value],[result]
  A. handle - 使用宣告的 handle 值
  B. member - 設定屬性的名稱
  C. value - 屬性的值。
  D. result - 回傳狀態 -1 表示有錯誤,0 表示沒有錯誤

錯誤訊息內容
5.CALL ui.interface.frontcall("WinCOM","GetError",[],[result]
  A. result - 錯誤的說明,如果沒有錯誤就為 Null

關閉 COM
6.CALL ui.interface.frontcall("WinCOM","ReleaseInstance",[handle],[result])
  A. handle - 使用宣告的 handle 值
  B. result - 回傳狀態 -1 表示有錯誤,0 表示沒有錯誤

以下就為 4GL 程式 Excel 資料匯入的範例:
DEFINE l_excelapp INTEGER,
               l_excelwb INTEGER,
               l_result INTEGER,
               l_str STRING,
               l_filename STRING,
               l_target STRING,
               l_range STRING

DEFINE l_i LIKE type_file.num5,
               l_j LIKE type_file.num5,
               l_column LIKE type_file.chr10
LET l_excelapp = -1
LET l_excelwb = -1

# 選擇檔案的位置和檔案名稱
LET l_filename = cl_browse_file()
# 建立 Excel Application 的 COM
CALL ui.interface.frontcall("WinCOM","CreateInstance",["Excel.Application"],[l_excelapp])
# 開啟所選擇的 Excel 檔案
CALL ui.interface.frontcall("WinCOM","CallMethod",[l_excelapp,"WorkBooks.Open",l_filename],[l_excelwb])
# 設定 Excel 要顯示
CALL ui.interface.frontcall("WinCOM","SetProperty",[l_excelapp,"Visible",true],[l_result])
# 讀取 Excel 的行數
CALL ui.interface.frontcall("WinCOM","GetProperty",[l_excelwb,'activesheet.UsedRange.Rows.Count'],[l_result])

FOR l_i=1 TO l_result
   LET l_column = l_i
   # 所要讀取的欄位,A 列第 n 行
   LET l_range = 'activesheet.Range("A',l_column,'").Value'
   # 讀取欄位的值
   CALL ui.interface.frontcall("WinCOM","GetProperty",[l_excelwb,l_range],[l_str])
   LET g_bmd[l_i].bmd01 = l_str
   # 所要讀取的欄位,B 列第 n 行
   LET l_range = 'activesheet.Range("B',l_column,'").Value'
   # 讀取欄位的值
   CALL ui.interface.frontcall("WinCOM","GetProperty",[l_excelwb,l_range],[l_str])
   LET g_bmd[l_i].bmd02 = l_str
END FOR

# 關閉 Excel 的 檔案和 COM
CALL ui.interface.frontcall("WinCOM","CallMethod",[l_excelapp,"WorkBooks.Close"],[l_excelwb])
CALL ui.interface.frontcall("WinCOM","ReleaseInstance",[l_excelapp],[l_result])

11 則留言:

  1. 您好,
    我在關閉EXCEL檔案和COM時,result回傳"-1",導致EXCEL程序卡在背景作業(工作管理員),不知道該用哪種方法排除?

    CALL ui.Interface.frontCall("WinCOM","ReleaseInstance",[xlapp],[result])
    CALL ui.Interface.frontCall("WinCOM","ReleaseInstance",[xlwb],[result])
    CALL ui.Interface.frontCall("WinCOM","ReleaseInstance",[xlsh],[result])

    回覆刪除
    回覆
    1. 補充:這個程序的位置在 C:\Program Files (x86)\Microsoft Office\Office12
      office的主目錄下。

      刪除
    2. 官方是寫 CALL ui.Interface.frontCall("WinCOM","ReleaseInstance",[xlwb],[result]) 的方式來關閉,
      我試過會關不起來,卡在背景作業中,
      範例就有寫用 CALL ui.interface.frontcall("WinCOM","CallMethod",[l_excelapp,"WorkBooks.Close"],[l_excelwb]) 就正常了。

      刪除
    3. 謝謝您的協助了,我趕快試試看。

      刪除
  2. 回覆
    1. 請問是 win7 和 office 2007 以後的版本嗎?
      我研究看看。

      刪除
    2. 我也遇到這問題,不知道有解嗎?

      刪除
  3. win7 & office2007 or 2010, 當oracle 的欄位有簡體字時, 寫到Excel某欄位變 ? 號,
    語法如下:
    CALL ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("A2").Value',"制令单号"],[result])

    回覆刪除
  4. LET l_value = sr1.ima02 # 產品品名的內容為 "太阳眼镜组"
    CALL ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("C' || cnt || '").Value',l_value],[result])

    回覆刪除
  5. win7 & office2007 or 2010, 當oracle 的欄位有簡體字時, 寫到Excel某欄位變 ? 號,
    語法如下:
    CALL ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("A2").Value',"制令单号"],[result])

    回覆刪除
  6. 請問有遇過 excel 2016 , 無法啟動的情形嗎?要做資料匯入時 CALL ui.Interface.frontCall("WinCOM", "CreateInstance", ["Excel.Application"], [xlapp]) 就失敗了。

    回覆刪除