Posts Tagged With: VBA

[VBA] 轉換 Json 字串到 Excel 表格


前篇:[VBA] 抓取 Json 檔案轉入 Excel

前篇的 Json 字串解析,是從 GitHub 上抓的,別人的程式碼用一陣子總覺得全身不舒服,前陣子要處理 OCPP 的 Json 字串時,就自己寫一個。

呼叫範例:

Sub CommandOpenFile(ByVal strCommand)
   Set tSheets = ThisWorkbook.Sheets(strCommand)
   strFileName = ThisWorkbook.Path & "\ocpp.log"
   strBody = myGetStringFile(strFileName)
   arrBody = Split(strBody, vbLf)
   ubl = UBound(arrBody)
   
   iRow = 1
   For ibl = 0 To ubl
      nLoc = InStr(arrBody(ibl), StringFormat(",{0}{1}{0},{", """", strCommand))
      If nLoc > 0 Then
         sLoc = InStr(nLoc + 1, arrBody(ibl), "{")
         eLoc = Len(arrBody(ibl)) - 1
         strValue = Mid(arrBody(ibl), sLoc, eLoc - sLoc + 1)
         Set pJson = ParseJson(strValue)
         
         If iRow = 1 Then
            uCol = pJson.Count
            arrCol = pJson.Keys
            For iCol = 1 To uCol
               tSheets.Cells(iRow, 1 + iCol) = arrCol(iCol - 1)
            Next
            iRow = iRow + 1
         End If
         
         For iCol = 1 To uCol
            tSheets.Cells(iRow, 1 + iCol) = pJson(arrCol(iCol - 1))
         Next
         
         iRow = iRow + 1
         Set pJson = Nothing
      End If
   Next
End Sub

我把我的 Json 解析獨立放在一個模組內,可參考下方網址

modJsonTool.bas: https://1drv.ms/u/s!AqdV_QuSGVQUy2eZgQaLJJb2BNbz?e=7xFSKW

這段的目的是我的 OCPP.log 是一個通訊過程的紀錄檔,裡面有多段的 Json 字串,大部分的指令所形成的 Json 都比較簡單,就用一個通用的副程式解析,把相同指令的 Json 解析都扔到相同的頁籤。

OCPP 內比較複雜的類似 MetaValues 指令,因為回傳的是樹狀結構,不是列狀 (Row) ,所以要挑自己要留的欄位轉到 Excel 內,就單獨另外寫一個 Sub 處理。

Json 解析我參照前篇的架構,屬於樹狀的資料 (以 {…} 包括) 用 Dictionary 去處理,屬於陣列的資料 (以 […] 包括) ,用 Collection 處理,解析的程式碼就用遞迴處理,所以主要的只有一個函數:

Function ParseJson(ByVal strJson As String, Optional ByVal rootDelimiter As Variant)
   JsonDelimiterInit
   ubd = UBound(jsonDelimiter)
   ReDim arrIndex(ubd)
   
   ReDim colTemp(ubd) As New Collection
   fmtKeepName = "(($VbaJson${0}${1}${2}$))"
   fmtKeepLeft = 11
   
   rtnValue = Empty
   strJson = TrimEx(strJson)
   lenJson = Len(strJson)
   pbd = -1
   startLoc = 0
   
   Do
      nowIndex = lenJson + 1
      nbd = -1
      For ibd = 0 To ubd
         arrIndex(ibd) = InStr(startLoc + 1, strJson, jsonDelimiter(ibd)(0))
         If arrIndex(ibd) > 0 And nowIndex > arrIndex(ibd) Then
            nowIndex = arrIndex(ibd)
            nbd = ibd
         End If
      Next
      
      If nbd = -1 Then
         ' 沒有括號裡面開始解析內容
         Exit Do
      Else
         ' 字串的引號裡面會不會有括號?
         startLoc = arrIndex(nbd)
         endIndex = FoundBlockEndIndex(strJson, jsonDelimiter(nbd), startLoc)
         
         If endIndex > 0 Then
            pbd = nbd
            colIndex = colTemp(nbd).Count + 1
            Select Case jsonDelimiter(nbd)(0)
            Case "{"
               strObjectName = StringFormat(fmtKeepName, "Object", nbd, colIndex)
            Case "["
               strObjectName = StringFormat(fmtKeepName, "Array", nbd, colIndex)
            Case Else
               Err.Raise &H80000001, , "Json 字串解析格式錯誤"
            End Select
            
            subJson = Mid(strJson, startLoc + 1, endIndex - startLoc - 1)
            strJson = Replace(strJson, StringFormat("{1}{0}{2}", subJson, jsonDelimiter(nbd)(0), jsonDelimiter(nbd)(1)), strObjectName)
            
            colTemp(nbd).Add ParseJson(subJson, jsonDelimiter(nbd))
         Else
            Err.Raise &H80000002, , "Json 字串缺括號 " & jsonDelimiter(nbd)(1) & ",字串內容為 " & strJson
            Exit Do
         End If
      End If
   Loop
   
   If lenJson > 0 Then
      ' 回傳物件
      If IsMissing(rootDelimiter) Then
         Set rtnValue = colTemp(pbd)(colTemp(pbd).Count)
      Else
         nowDelimiter = rootDelimiter(0)
         
         Select Case nowDelimiter
         Case "{"
            ' Set rtnValue = New Dictionary ' 需在 選單 工具 設定引用項目 引用 Microsoft Scripting Runtime ,使用其中 Dictionary 類別
            Set rtnValue = CreateScriptingDictionary()
         Case "["
            Set rtnValue = New Collection
         End Select
         
         ' 解析內容
         arrItems = Split(strJson, ",")
         ubi = UBound(arrItems)
         For ibi = 0 To ubi
            arrItems(ibi) = TrimEx(arrItems(ibi))
            
            Select Case nowDelimiter
            Case "{"
               itemRow = Split(arrItems(ibi), ":")
               ubr = UBound(itemRow)
               If ubr > 1 Then
                  For ibr = 2 To ubr
                     itemRow(1) = itemRow(1) & ":" & itemRow(ibr)
                  Next
               End If
               
               For ibr = 0 To 1
                  itemRow(ibr) = TrimEx(itemRow(ibr))
               Next
               itemKey = TrimEx(itemRow(0), TES_SepcialAdd, , """'")
               strItem = itemRow(1)
            Case "["
               itemKey = CStr(ibi + 2)
               strItem = arrItems(ibi)
            End Select
         
            If InStr(strItem, Left(fmtKeepName, fmtKeepLeft)) >= 1 Then
               arrRow = Split(strItem, "$")
               Set itemValue = colTemp(CLng(arrRow(3)))(CLng(arrRow(4)))
            Else
               strValue = TrimEx(strItem, TES_SepcialAdd, , """'")
               If Len(strValue) < Len(strItem) Then
                  itemValue = strValue
               Else
                  itemValue = CVariant(strValue)
               End If
            End If
            
            Select Case nowDelimiter
            Case "{"
               rtnValue.Add itemKey, itemValue
            Case "["
               rtnValue.Add itemValue, itemKey
            End Select
         Next
      End If
   End If
   
   Set ParseJson = rtnValue
   
   Set rtnValue = Nothing
   For ibd = 0 To ubd
      Set colTemp(ibd) = Nothing
   Next
End Function

每一層物件對應到 Json 每一層。

由於用遞迴函數,如果碰上我還沒遭遇過的特殊字串,可能會卡在裡面,建議在這個函數裡面加 DoEvents ,若遭遇到無窮迴圈時,可以透過除錯模式跳出,加入特殊字串處理。

GitHub 範例要求要在 VBA 專案參照物件 (提早連結),好處是執行效能比較快,缺點是不熟的人不會處理,特別是 VBA 的安全信任一直調整,所以我改成延後連結的方式處理:

Function CreateScriptingDictionary() As Object
   Set CreateScriptingDictionary = CreateObject("Scripting.Dictionary")
End Function

目前遭遇過特殊字元已經納入處理的有這個陣列:

If Not IsArray(jsonEscape) Then jsonEscape = Array(Split("\""|\\|\/|\b|\f|\n|\r|\t", "|"), Array("""", "\", "/", Chr(8), Chr(12), Chr(13), Chr(10), Chr(9)))

我自己之後會持續使用自己程式碼,擴大支援範圍。

Categories: 工作點滴, 技術分享 | 標籤: | 發表留言

[VBA] 抓取 Json 檔案轉入 Excel


周一同事說,有個政府網頁的數據因為直接 Show 圖上,當滑鼠停在上面才會跳出數據,所以必須一筆一筆透過移動滑鼠來讀取並記錄。我回覆說,可以把網頁提供給資訊部,看看能不能協助存取。

昨天我收到網址,並由同事告訴我她要抓甚麼數據,確認後,開啟 Edge 的開發者模式,馬上就確認是透過 AJAX 讀取資料更新畫面。

用 Edge 測試了幾個網址,資料內容是 Json 格式,都可以直接撈出來,大概沒啥阻擋,打算用過去寫好 .Net framework 的 WebClient 去抓,一測試,WebClient 連線能建立成功,但是無法取得資料流,檔案大小都是 0 到逾時。


註:寫部落格時才想到,可能是 https 加密問題… 參考先前紀錄:

[CLR] .Net framework 2.0 WebClient 連接 https


剛好我以前是用 VBScript 寫過 AJAX ,有現成程式碼拷貝到 Excel 去測試,在 Excel 測 xmlhttp 抓資料就正常,所以可以推論這個網站有針對 http protocol 的 Header 做偵測與阻擋。

透過 xmlhttp 抓 AJAX 取得 Json 資料後,問題在 Json 解碼,這個在 GitHub 有現成程式碼可以引用:

GitHub – VBA-tools/VBA-JSON: JSON conversion and parsing for VBA

我直接引用他寫好的 JsonConverter ,見下圖的專案視窗。

上面網址的最下方說明,要同時引用他另一個專案:

GitHub – VBA-tools/VBA-Dictionary: Drop-in replacement for Scripting.Dictionary on Mac

我在 Excel 365 跑這段程式碼的時候,會因為他自建類別 Dictionary ,與 Scripting.Dictionary 不相容,所以我去修改他的類別,把原始 Scripting.Dictionary 透過 .This 丟出來,就可以順利的完成執行。

主要程式碼如下圖:

VBA 透過 XmlHttp 抓取 AJAX 資料並分析匯入

順利把 Json 共 24 欄 12,313 列資料匯入 Excel 。

已匯入的原始資料

Categories: 工作點滴, 技術分享 | 標籤: | 1 則迴響

[VBA] 替巨集簽署數位憑證方便存取


最近在論壇看到一堆問 Excel 巨集無法被信任問題。

對使用者自己來說,巨集可能很好用,所以希望隨心所欲的使用,對作業系統的安全性來說,巨集就可能潛藏外部危害,中毒就怪微軟。所以微軟一直在調整巨集安全性,降低中毒潛在風險,提高作業系統安全,但對使用者來說,就是越來越難用。

很多範例是走信任路徑,我個人是反對走信任路徑,比如說公司伺服器的路徑被同仁信任了,如果這個路徑被塞入惡意巨集時,因為路徑被信任,就會無法防護。

我個人是偏向開發人員應該替巨集簽署數位簽名。

這個議題在過去本網誌也多所提及,不過隨著 Office 版本更新,舊版本可能對使用者要做觀念轉換,本篇用 Office 2019 的 Excel 為範例說明。

數位憑證來源很多,可以用買的,可以用自然人憑證 (請搜尋本網誌先前說明),當然也可以用免費的,本篇是以 Office 免費的憑證為範例,所以這是 Office 預設功能,不是為了解決問題,創造更多問題。

Office 2019 x64 的免費憑證產生器在下列路徑,如果不確定 Office 版本及位元版本,建議用檔案總管搜尋「selfcert.exe」

selfcert.exe 的路徑

接下來依步驟產生,第一步就是建立憑證名稱,最好取個有識別性的名稱,範例就隨便取了。

建立憑證名稱

一個步驟就可以建立憑證。

憑證建立完成

開啟一個未被信任的巨集檔案,這是在公司內部教育訓練的一個範例檔,使用 FSO 做檔案清單,包含子目錄搜尋,方便同仁建立檔案對照表用。

未被信任的巨集檔案

從 IDE 介面選單 > 工具 > 數位簽名

選單位置

預設是沒簽名的,簽名過的檔案會顯示已簽名的內容。

選擇數位憑證進行簽署

選擇剛剛產生的數位憑證,如果憑證超過一個,點選其他選擇可展開來選其他憑證。

選擇數位憑證進行簽署

簽署完的檔案記得存檔。

顯示已簽署的數位憑證

通常開發過程已經信任了開發中的巨集檔案,所以若要測試憑證是否正確被信任,需要先清除信任,這個功能會清除所有被信任的檔案,所以建議另外準備測試電腦測試,不要在平常工作電腦測試,否則所有曾經被信任過的檔案都需要重新信任。

移除所有信任的巨集檔案

透過 [控制台] > [網際網路選項] > [內容] > [憑證] 可以管理憑證。

如果找不到控制台,先開啟檔案總管,直接在網址列輸入 [控制台] 即可。

憑證管理

Windows 11 的憑證管理畫面如下。

Windows 11 叫出網際網路選項後就能進入憑證管理。

這邊可以看到先前建立的憑證出現在這。

自建免費憑證會出現在個人區

舊版的 Office 可以在開啟帶有數位憑證的巨集將該憑證直接進行信任,新版本的 Office 移除該功能,所以必須把數位憑證匯出後,散佈給使用者匯入,使用者匯入後,凡是經由該憑證簽署的巨集檔案,就直接可以使用,不用再經過確認。

開始匯出憑證

依畫面逐步操作。

Office 的免費憑證沒有私密金鑰

依預設值匯出。

依預設值選擇匯出格式

選擇匯出路徑。

選擇路徑

完成憑證匯出。

完成憑證匯出

匯出成功。

匯出成功

憑證匯出後,就可以散佈給使用者匯入,但開發電腦已有憑證,必須先刪除才能測試使用者端的情境,所以在這邊先刪除,開發者千萬注意,開發電腦請不要刪除憑證,這個憑證匯出後再匯入,不能再被來用來程式碼簽署,所以千萬不要刪除,除非只是打算測試,刪除後必須重新產生新的憑證進行簽名,即使名稱一樣,因為實際隨機金鑰不同,仍然會被視為新憑證,需要重新散佈。

刪除憑證從上面憑證管理畫面進入進行刪除。

開發電腦千萬不能刪除憑證

刪除憑證後,數量比上面的圖片少一項。

已刪除剛建立的免費數位憑證

接下來測試使用者的匯入,一般被散佈的對象直接從這個步驟執行。

從上面憑證管理畫面,選擇受信任的發行者後選擇匯入。

選擇受信任的發行者

憑證匯入逐步執行。

匯入憑證

使用者將收到的憑證檔案存檔後,依路徑選擇進行匯入。

從路徑匯入

確認匯入的位置是 [受信任的發行者]

匯入受信任的發行者

即將完成憑證匯入。

即將完成憑證匯入

憑證匯入成功。

憑證匯入成功

可看到憑證正確匯入,其他的憑證是相關軟體的原廠憑證。

憑證匯入成功

直接開啟剛剛簽署好數位憑證的巨集檔案,可以看到直接進入,無須再信任。

已被信任的巨集檔案

檢查 Excel 信任中心,可看到數位憑證已被信任。這邊需要特別注意,因為是信任憑證,所以是對電腦所有依據憑證授權的都生效力,比如說 Word、PowerPoint 的巨集若是簽署相同的數位憑證,也會直接被信任。

已被加入受信任的發行者

重新被匯入的數位憑證不能被用來簽署程式碼,因此不用擔心散佈憑證會被其他人再利用。

先前產生的免費數位憑證刪除後再匯入就不能再被用來簽署

分別測試不同的位置,看看是否可以被信任。這是透過網路芳鄰 (SMB) 上的路徑 (UNC) 進行測試,可直接被開啟執行。

透過 Nas 存取巨集檔案

透過 OneDrive 同步路徑進行測試,可直接被開啟執行。

OneDrive 同步路徑

透過 OneDrive 網頁進行測試,可直接被開啟執行。

OneDrive 網頁

我 Google 雲端沒裝同步軟體,所以可以當作是一般網頁下載進行測試。

Google 雲端硬碟

一般網頁下載檔案仍受限 Windows 內建功能會被阻擋,可以點選啟用編輯。

預設阻擋來自網路的檔案

選擇解除封鎖後,亦可直接執行巨集檔案。

從檔案總管選擇解除封鎖

我個人比較偏好從數位憑證簽署來讓巨集檔案安全被散佈,若有簽署數位憑證的檔案,必須由開發人員才能存檔,可以確保檔案散佈後不會被修改。

Categories: Office, 技術分享 | 標籤: | 2 則迴響

[VBA] Office 自動化的必要免費開發手冊


微軟的開發文件不斷的統合,目前最新版的基本上只有線上手冊,放在:

https://docs.microsoft.com/zh-tw/visualstudio/vsto/getting-started-office-development-in-visual-studio

早期的文件中,建議務必取得的是 Office 2003 SP3 內含的附屬文件,從安裝完成檔案抽出來,可以更方便的運用。

早期多數人開發過程中很少按下 F1 瀏覽離線版的線上手冊,更不要說備份下來隨時翻找,我自己當時也沒做,但因為有相容測試需求,有留虛擬機,還好可從虛擬機裡面抽出來。

後續微軟文件大多數改線上版,為了配合線上版,反而短少物件架構圖,有點可惜。

我自己是定時會將新的線上手冊複製下來統合在一個目錄:

備份存放線上手冊的目錄結構

再使用 Windows 內建的快速工具列做超連結,以便隨時查閱:

快速工具列超連結到線上手冊

下面列舉幾個需要它的截圖。

我覺得最重要的功能就是有 Office 所有物件的物件架構圖。這在 Office Automation 開發中非常發便,甚至不限於 VBA/VB6/VBScript 開發,對 .Net framework 下支援 COM 的各語言也非常方便,例如 VBNET/C# 等,對於 C# 來說,還是要呼叫 Office COM 內的方法、屬性、使用事件等,但對於新版的線上手冊來說,沒有物件架構圖很不容易找到對應的需求。

Office 2003 Excel 物件架構圖

中文的線上說明,這部分在新的線上手冊效果遞減,早期線上手冊放在 MSDN 下,幾乎是只有英文說明,當然多數的開發者能閱讀英文說明,但畢竟沒有中文說明更親切。

我比較喜歡當時的次要查詢,例如下圖,點擊多重物件可以跳出 Document 下的各子物件或集合物件,新版的線上手冊都統合到屬性去,找起來比較困難。

Office 2003 Word 子物件 Doument

操作快速。離線式的線上手冊,永遠比在線式的線上手冊快,而且可以在無網際網路情況下開發,特別適合於有管制網路的環境。

例如,Access 附 SQL 語法說明手冊,入門 SQL 語法,這個線上手冊很不錯,雖然不是 ANSI SQL 1992 以後相容語法,但是差異不大。而且也可用來比對 Access / Excel 透過 OLEDB / ODBC 不同語法的差異,這個檔是相容於 OLEDB 的。

Office 2003 Jet/Oledb SQL 語法說明

Office 2003 SP3 是有完整中文線上手冊說明的最後一版,新版的線上手冊就多數是英文手冊了,要看中文版可能要到本篇最前面介紹的網址看。

Office 2019 使用 ADOX 建立空白的 mdb 檔案

例如 Visio 2013 中文版只有英文線上手冊,就沒有物件架構圖,我覺得不好用。

Office 2013 Visio Document 物件說明

新版 Office 仍有少數中文線上手冊,例如部分人愛用的條碼控制項。

Office 2019 內的條碼控制項說明

如果不是使用 VSTO ,除了 Office 內件線上手冊外,Script 5.6 的線上手冊也很重要。

例如有名的物件 FileSystemObject(FSO) 就可以在 VBA 內使用。

Script 5.6 FileSystemObject 的子物件

VB6/VBA/VBScript 對於檔案處理並不友善,例如先前在這篇

[VBA] Excel 安全性調整後,跨檔案所需要的變更

內部教育訓練的案例3 截圖中,需要整理檔案清單給業主,或是資訊循環中,需要整理系統文件的檔案清單給內稽、外稽檢查,那麼這時候使用 Excel VBA 做成一個常用巨集檔,就會很方便的產生檔案清單。

例如用教育訓練的案例3 產生這篇文章線上手冊的檔案清單如下圖。

線上手冊的檔案清單

案例3 呼叫 FSO 的 myDir 。

呼叫 FSO 的片段程式碼

除 FSO 外,也可以在 Script 5.6 找到 JavaScript 的說明跟通用運算式的說明。

VB6/VBA/VBScript 裡面的 Find/Replace 是比較陽春的掃描搜尋方式,而 JavaScript 直接就是使用通用運算式搜尋,無疑效能、彈性提高很多,所以要在 VBA 內使用通用運算式,要參照 Script 5.6 手冊。

Script 5.6 JavaScript 與 VBScript 可用的通用運算式

另外還有一些當年很好用,現在幾乎是廢棄的線上說明。

比如說 OWC 當年是一個很好的 COM 元件,可用在 VB6 / VBA / VBScript / VBNET 中,可用在 ASP/ASP.NET Web 的 Server 端輸出圖形,也可以用在 client 端當 ActiveX 用,簡直百搭,SQL Server 2008 R2 以前內建支援 OWC,但也隨著時代淘汰。

Office 2007 OWC 12 線上手冊

當年還有一個 MODI 元件很有用,可以給 VB6/VBA/VBScript/VBNET 等支援 COM 語言使用,例如將一張掃描的圖片做 OCR 轉成文字,但在 Office 2007 被微軟淘汰,用 OneNote 取代,當年 OneNote 的辨識率還不如 MODI。

Office 2003 MODI 的 VBA 開發手冊

微軟有很多很不錯的離線式的線上手冊,多數人沒看過就消失,對於開發者來說,這都是一些很重要的參考文件,如果需要,不妨在虛擬機上安裝舊版的 Office ,把相關文件備份出來參考。

Categories: Office, 技術分享 | 標籤: | 發表留言

[VBA] Excel 安全性調整後,跨檔案所需要的變更


我大概是 Excel 4.0 開始用巨集的,到了 Excel 5.0 (Office 4.2 / 4.3) 轉成 VBA 以後,我就比較經常用,那時 Word 6.0a 的巨集還不是 VBA ,而是 WordBasic ,到 Office 95 才統一為 VBA 。

1996/07 碩畢當兵前要交接研究資料給學弟時,寫了一篇做內部教育訓練。

MS Office 自動化巨集 http://www.hisdt.com/TLCheng/Basic/Office/officevb.htm

這篇是在 1999/02/03 網頁化上網分享,念碩士的時候還是 Excel 5.0 + Word 6.0a ,做研究計畫、論文會大量用到 Excel 整理數據,例如我的碩士論文是做人工智慧,用 VB3 寫類神經網路 (BPN) 跟自己修改的模型 (有點類似現在的 RNN) ,在下班後,丟到一堆助理的電腦上去跑,借同學的電腦夜間跑,白天一早來暫停目前類神經網路學習進度儲存後,備份計算結果各台電腦還給大家用,白天我則利用 Excel VBA 整理數據出表格、圖形自動貼到 Word 印出後,跟指導教授討論。

工作後寫 Excel VBA 的機會變少,有大量資料要分析的時候,我才會拎出來用。

Office 2007 以後,基於安全考量,有 VBA 的檔案要存成 .xlsm ,我也開始養成慣例,把 VBA 單獨寫成一個檔案,資料檔跟輸出檔分在不同的檔案,方便安全管理,大概是前三年左右吧,不知道 Excel 哪個安全性更新起,存成 .xlsm VBA 裡面的函數就不能跨黨案使用,必須存成 .xlam 做成增益集。

我以前個人基於安全考量,希望 Excel 開起來是乾乾淨淨的,所以一直沒做成增益集來用,但 Excel 內有些函數功能真的不足,還不如呼叫 VBA 內建函數,所以我就把我常用的 VB 內建函數跟自己常用的函數建成一個 VbaTools.xlam 來引用。

一個新的 .xlsm 開發完成後,可以另存新檔為 .xlam ,這時 Excel 會自動導向存放增益集的路徑,我習慣放在我個人區,移動到其他台電腦用複製貼上即可,但是預設不會啟用,要自己勾選起來。

個人區域設路徑為 %AppData%\Microsoft\AddIns

開啟 Excel 後,左上角 選單 > 檔案 > 選項 > 增益集

自訂增益集

找到自己的增益集後,下方 [管理] 選擇 [Excel 增益集] ,選擇 [執行]。

如果沒有正常出現自己的增益集,可從右側 [瀏覽] 按鈕下去尋找。

勾選自己的工具

勾選後按下確定即可。

接下來就可以在任意檔案中呼叫增益集內的函數。

呼叫增益集內的函數

比如說 Excel 內的 REPLACE 函數,一次呼叫只能替換第一格發現的字串,但是 VBA 內建函數可以一次替換所有可發現的字串,一下子就方便不少。

所以我在前年寫了個兩小時教育訓練排在去年執行,主要是讓同事知道 Excel 還能做甚麼,針對大量重複的行政作業或流程,有需要找資訊部開發。

Excel VBA 內部教育訓練簡報檔

前兩個月執行老闆叫我進行的分析,因為資料量滿大的,所以我在其他 .xlsm 的巨集打算呼叫 VbaTools.xlam 時,發現居然不能直接呼叫。

開啟舊的兩個 .xlsm 也不能互相呼叫了。

我過去的慣例是會把共用的函數 .xlsm 另外開一個檔,專用的函數 .xlsm 自己存一個檔,自先前改用 VbaTools.xlam 後,就把共用的函數轉移進去,而且我記得先前還能用。

兩年前在寫這篇時:

[Excel]白做工了,規劃求解與 VBA https://tlcheng.wordpress.com/2019/05/12/excel%e7%99%bd%e5%81%9a%e5%b7%a5%e4%ba%86%ef%bc%8c%e8%a6%8f%e5%8a%83%e6%b1%82%e8%a7%a3%e8%88%87-vba/

用 測試.xlsm 還能呼叫 規劃求解 的 VBA 函數,連程式碼截圖都在,我也不知道為啥就不行了。

經搜尋新的方案是要加入參照才能呼叫其他 .xlsm / .xlam 的函數:

參照 VbaTools.xlam

參照完舊可以在瀏覽物件瀏覽程式庫時,看到 VbaTools.xlam 函數。

程式庫瀏覽

這個月還沒想到要寫甚麼,怕忘記 Excel 的 VBA 變化,寫下來提醒自己。

Categories: Office, 工作點滴, 技術分享 | 標籤: | 1 則迴響

[SQL] 透過 Access 轉換資料庫架構


有個客戶要結束節能業務,把他們的節能服務轉交給我們公司,他們原先的雲端監測系統阿祖 (Azure) Web Server 與 SQL Server 都要關閉,要由我們的監測系統自己處理。

它們的系統是現場 IPC 沒有查詢展示介面,監測資料在現場暫存後,就上傳到雲端資料庫,所以雲端資料庫每分鐘一筆,主要的資料表架構如下,每個月一個資料表:

分區視別字串點位識別字串資料時間值(字串)原始值(字串)
長度100最大長度50DateTime長度50長度50

所以在上面這個資料表架構下,每個月大概七百萬筆資料,約佔用空間500MB。

看了對方資料架構我才知道,為何對方網頁限制每次查詢時間間隔不能超過七天,而且每次查詢起來大概要跑 3 分鐘才會出來。

我的架構分成兩部分,現場端有IPC安裝 SQL Server Express資料庫,每分鐘一筆,統計分析後上傳到雲端資料庫,不同時間間隔分開放,以小時、日、月、年為單位統計。現場資料庫考慮效能及容量,將點位抽出來列表,核心資料表則所有時間放在一起不分表,資料架構大概是:

資料時間點位1點位2點位n狀態
DateTimeDoubleDoubleDouble長度n

所以每月大概變為43200筆,約佔用空間 50 MB。

所以需要將資料格式進行轉換,將對方類似一維的數值表格架構轉成我的二維的數值表格架構。

首先先將對方的 Azure SQL Server 整個備份到我電腦的 SQL Server Developer,光是做這件事,我電腦硬碟就被吃掉 40 GB …

考慮到我電腦內的資料庫避免異動,確保乾淨,所以我不打算在 SQL Server 處理資料格式轉換,我打算把每個月的資料匯入到 Access 後再轉換成我要的格式。

Access 轉換的架構

查詢「刪除 data 資料」這個並不需要存在,是我開發過程期間測試 SQL 語法用的。

資料表 raw 是用來放置 SQL Server 的匯入暫存資料,資料表 data 則是樣本資料表,為了快速處理,我還是依照每個月複製貼上 Data_yyMM 資料表,進行格式轉換,最後再統一匯入一個資料表。

所以核心的程式碼很單純:

DoCmd.SetWarnings False ' 關閉告警視窗
DoCmd.RunSQL nowQuery ' 執行 SQL 語法
DoCmd.SetWarnings True ' 恢復告警視窗

所以上述部分迴圈的目的就是為了組合 SQL 語法來達成目的,所以後面說明就專注於 SQL 語法,而非 VBA 語法。

匯入資料到 raw

將 SQL Server 資料表資料匯入到 Access raw 資料表,SQL 語法如下:

INSERT INTO [raw]
SELECT 點位識別字串,資料時間,值
FROM [來源表格名] IN " [odbc; Driver=SQL Server Native Client 11.0; Server=(local); Database=資料庫; UID=帳號; PWD=密碼; ]

注意到了嗎?這邊最特別的就是 IN 子句,透過 IN 子句跨越資料庫,這功能只能在 OLEDB 資料庫驅動程式下用,所以表示 Access 內 VBA RunSQL 是跑 OLEDB 來做查詢,這部分說明沒寫,這段應該是這篇的精華。

對 In 子句延伸閱讀可在部落格右側搜尋輸入:In 子句。

插入時間

為了避免無效時間,所以先在 data 資料表內將時間插入,並可確保所有時間都不被遺漏,SQL 語法如下:

INSERT INTO [Data_yyMM]
SELECT DISTINCT 資料時間 FROM raw ORDER BY 資料時間

更新各欄資料

這邊就依據資料點位對應到資料欄位,逐欄更新,所以前一步插入時間很重要,插入時間後,就有 PK 欄可供 UPDATE 使用。逐欄迴圈 SQL 語法如下:

UPDATE [Data_yyMM]
INNER JOIN (
SELECT 資料時間, 值 FROM raw WHERE 點位識別字串="點位代碼"
) AS tabData ON ([Data_yyMM].rdate=tabData.資料時間)
SET [Data_yyMM].點位i = tabData.值

透過前一步的插入時間做為 PK 值 JOIN ,就可以整欄資料直接轉移。

刪除 Raw Data

這段 SQL 語法太簡單,應該無須解釋。

DELETE FROM raw

小結

所以就能快速透過 Access 執行巨集持續進行不同資料表的資料匯入、表格架構轉換,不過雖然有跑刪除 Raw Data ,但還是無法防止 Access 長大,因此長大到 2 GB 時, VBA 會被中斷,重新壓縮 Access 檔案,再改回圈開始處,就可以繼續往下跑。

我這時會先把 Data_yyMM 搬到其他 Access 檔案,把這個轉換用的 Access 盡量空出來跑資料轉換,不過我把 Data_yyMM 合併的 VBA 也寫再這個轉換檔,所以最後我會把所有 Data_yyMM 搬回來合併。

Categories: 資料庫, SQL, 工作點滴, 技術分享 | 標籤: | 發表留言

[Excel]白做工了,規劃求解與 VBA


很久沒有做分析了,都在 code …

上個月老闆交代我做個分析,想來想去,想要最佳化還是用數學規劃,線性規劃是個快速解決問題的方法,只要問題不複雜,直接用線性規劃求解就可以了。

問題是離開學校後,沒有好的軟體可以算線性規劃,想起來還有 Excel 的規劃求解可以用,就翻開 Excel 玩。

話說 2005 年在新加坡 MVP亞洲年會中,跟當時負責中文化的洪士吉老師與這個巨集的澳洲原作者聊過,當時聽洪士吉老師有原始碼跟密碼,我那時自己也用 VBScript 寫一個線性規劃的 ASP 線上網頁,所以主要討論的是卡曼卡法的加速解跟 Lindo,但是我論文不是搞這方向,離開學校後就甩到邊邊角角了。

我平常為了加速 Excel 開啟,所有的增益集都關閉,Office 2003 年代短暫的玩過規劃求解,但主要還是玩 Lindo ,開啟規劃求解增益集後,發覺設定方式完全不一樣了,看了一下線上手冊,上面寫 Excel 2010 後改成這樣,只好重新學習。

首先,先把自己寫的線性規劃翻出來,用相同的模型建構 Excel ,自己會比較容易上手:

線性規劃命題範例

按下 [進行最佳化分析] 後,可得到計算結果:

線性規劃計算結果

這個命題是在做教材範例,假定一個有閘門的滯洪池或水庫,在已知預報進水量下,受到滯洪池蓄洪量、放水路放水等限制,目標是穩定洩水減低洪害,各限制式的依據參閱上面網頁擷圖右側文字說明。

下面是我喜歡的規劃求解表格樣式,規劃求解仍然使用 Excel 公式,所以並沒有需要排得整整齊齊,但是為了人類容易閱讀,還是排成表格方式比較不會錯,詳細個位置說明,放到最後,先看操作步驟:

在 Sheet 上建立規劃求解命題

從 選單 點選 [資料] > [規劃求解] ,逐項設定:

規劃求解設定

規劃求解計算約 1 秒內可完成:

規劃求解完成

計算結果與設定對話盒連結註記說明:

規劃求解計算完成
  1. 圖上數字對應到 [規劃求解參數] 對話盒的數字,並不對應到這邊說明的項次。
  2. 變數名我選擇放在第一列,C1 ~ J1 ,這種架構大家都容易看得懂。
  3. 變數計算結果我選擇放在第二列,C2 ~ J2,預設可以不輸入,參見前面建立命題的圖,不輸入,就代表起始解為 {0} 集合。
  4. 目標函數的係數我放在 C3 ~ J3,也就是 MIN C。
  5. 限制式左側的係數我放在 C4 ~ J19 ,不等號我放在 M4 ~ M19,常數項我放在 N4 ~ N19。
  6. 最佳化可以在 [規劃求解參數] 輸入 Excel 公式,但這樣會造成每次設定的複雜化,比如說目標函數一變,或是限制式調整時, [規劃求解參數] 的設定就要跟著變,所以為了方便起見,建議像我這樣做,在 K3 輸入陣列公式,讓係數乘變數,就可以降低 [規劃求解參數] 的設定問題,K3 正確設定完成後,複製到 K4 ~ K19 ,讓限制式的係數一樣可以乘變數。注意,陣列公式輸入完成後,要按下 {Shift}+{Ctrl}+{Enter} 三個鍵,才能正確變成陣列公式。
  7. 最後在 [規劃求解參數] 對話盒 [載入/儲存] 按鈕,點下 [儲存] ,選擇 N2 。

這個計算結果,可以透過 K/L/M 三欄檢查限制式是否成立,或是直接觀看 N 欄,限制式成立的邏輯公式就是使用 K/L/M 三欄。

在說明項目 6 中,使用了陣列公式,實務上會增加計算量,也就是係數 0 x 變數,但卻可以讓設定參數簡易許多,就如同本例。

做到這,可以發現 L 欄用不到,因為在 [規劃求解參數] 對話盒 [新增] 限制式時,都要手動輸入,我的目的是要解決老闆交付的任務,所以針對此命題範例建立了測試的 VBA 程式碼,細節到正式命題再修改:

用 VBA 建立規劃求解參數

為了方便起見,我在 VBA 內直接建立陣列公式,也就是說上面建立規劃求解的途中,K 欄不用輸入,其他 [規劃求解參數] 對話盒的輸入,都用 VBA 自動產生。

規劃求解不支援直接輸入不等式,所以用 GetRelationIndex 函數將不等式轉成索引值輸入。

如果不想自己打太多程式碼,可以用錄製的再進行修改,不過這張圖上的程式碼已經很精簡了,錄製會很亂,不如直接打,再改欄位值即可。

規劃求解的函數使用說明參考微軟官方網址:https://docs.microsoft.com/zh-tw/office/vba/excel/concepts/functions/using-the-solver-vba-functions

好了,終於開始建立正式命題,先把正式命題縮小為一天24小時的時資料進行連續量分析,建個小小的模型,測試看看是不是能正常運作:

規劃求解超過上限

不得不爆粗口…

「規劃求解限定為 200 個變數儲存格和 100 個限制式,加上變數儲存格的限值。」

100 個限制式?這個規格限制下,根本是玩具吧… 規劃求解,我只好繼續把你放生了…

[2019/06/05]

花了點時間,把網頁版 ASP 的 VBScript 轉成 VBNET 語法,順便把命題轉成類別,測試還算成功。

VBNET WinForm 輸入命題
VBNET WinForm 輸入命題

輸入完線性規劃命題後,點選 [限制式] 頁籤 下方工具列那個圖示 (測試程式沒有管 Icon 的美觀度) ,即可得到輸出結果,輸出改用 StringBuilder 產生 HTML 語法用 WebBrowser Control 輸出,這樣之後若有需要,可以在工具列放預覽列印的按鈕,呼叫 WebBrowser Control 的預覽列印。

VBNET WinForm 輸出結果
VBNET WinForm 輸出結果

不過裡面還有一些 Bug ,大型命題解不出來,這就造成除錯困難,大概還要加一頁來輸出線性規劃各步驟階段的計算表格,才好除錯。

Categories: Office, 工作點滴, 技術分享 | 標籤: | 8 則迴響

[VBA] Office 2013 x64 以後版本呼叫 Windows API 要加關鍵字 PtrSafe


工作上有一個很少用的工具 Excel 巨集,裡面放了一堆 API ,是以前寫的。

這兩天臨時要用到,用 Excel 開起來後,一片滿江紅,下面的圖檔是我處理完後加個測試行做出來的,檔案就跟第一行一樣,宣告區全是紅的。

Office 2013 VBA 版本

Office 2013 VBA 版本

從版權畫面可以看到,VBA 7.1 的大版本懸掛在那。

滿江紅是看不出來要改啥,所以上網查半天,詳細說明請參考 MSDN 線上手冊:

Delare 陳述式 https://msdn.microsoft.com/zh-tw/library/office/gg278581.aspx

搞定後才發現,重新輸入程式碼,換行時,VBA 程式碼自動檢查就會提醒你,在 Office x64 下,要加 PtrSafe :

自動提醒要加 PtrSafe

自動提醒要加 PtrSafe

可以比對 [錯誤] / [視窗] 兩行宣告,就只差在 PtrSafe ,錯誤那行沒有輸入 PtrSafe 就會跳錯。

所以也可以推知,舊版本的 VBA 在 x64 下,若有呼叫到 Windows API 都須修改宣告,否則根本不能跑,可能非微軟的協力廠商,例如 AutoCAD 也受此影響。

當然又回到那句老話,這樣看來,微軟十年前根本是騙大家的,VB6 要上到 x64 還是有很多解法,就看微軟願不願意而已,因為在 Office 中已經解決了阿~

微軟不再支援 VB6 的理由,又消滅了一個…

Categories: Office, 技術分享 | 標籤: | 發表留言

[VBA] 回傳到 Sheet 的陣列索引值下限會自動從 0 變更為 1


這篇跟前篇有點關係:[VBA] LongLong 超長整數 我打算將監測數據依據是否超越門閥值來轉換成旗標變數。 由於 Excel 內沒有 Array 這個函數,所以我在 VBA 裡面加了一個 VbaArray 函數來呼叫 Array 給 Excel 呼叫。

Function VbaArray(ParamArray arrayData())
  ReDim rtnArray(0 To UBound(arrayData))
  For ibd = 0 To UBound(arrayData)
     rtnArray(ibd) = arrayData(ibd).Value
  Next
  VbaArray = rtnArray
End Function

也就是直接包裝 Array 而已,沒啥特別的。 透過這個函數,我在 Sheet 內呼叫我的旗標轉換函數,由於 VB6 以後,未明確宣告陣列索引下標者,均為 0 ,VBScript / VBNET 則強制為 0 ,沒有陣列索引下標可以不為 0 ,因此習慣這個體驗,直接用:

For i = 0 To UBound(arrData)
   ' 略
Next

然後 Excel 回傳 #VALUE … 用除錯模式追蹤,居然問題出現在 arrData(0) 陣列索引錯誤?立刻在立即除錯測試 LBound(arrData)、UBound(arrData) 與我的認知完全不同,所有索引值都增加了 1 ,也就是說從 Base 0 變成 Base 1 。 寫了小的測試 Excel 2013 (VBA 7.1) 的檔案如下圖:

Excel 2013 經過 Sheet 陣列索引值變更了

Excel 2013 經過 Sheet 陣列索引值變更了

GetSecond 變成取第一個。 我以為是 Excel 2013 的 bug ,找台 Excel 2003  (VBA 6.5) 測試,也是相同狀況:

Excel 2003 經過 Sheet 陣列索引值變更了

Excel 2003 經過 Sheet 陣列索引值變更了

所以此行為是設計行為,透過 Google 搜尋微軟站台相關說明。 Support 那邊有相關的,但並沒有很明確提醒這個狀況:https://support.microsoft.com/zh-tw/kb/213798

論壇則有人因為跟 VBNET 慣例不同,提出疑問:https://social.msdn.microsoft.com/Forums/en-US/8155cfa8-7b9f-4a55-ba46-45bddcb77779/array-dimensions-mismatch-between-excel-and-net-vb-2010?forum=vbinterop

我猜可能是為了相容 Excel 5.0 預設採用 Base 1 吧?不然也沒得猜了。 做個紀錄,以後不會再犯相同狀況。

Categories: 工作點滴, 技術分享 | 標籤: | 發表留言

[VBA] LongLong 超長整數


話說,公司的專案支援 VBScript 外掛,這幾天在用 Excel 2013 的 VBA 7.1 寫 VBScript 。

因為裡面要用到位元旗標,我就很順手的打了:
2^i

想說,VBA 原始碼自動感知會幫我加空白,就繼續往下寫。

寫完以後用 Excel 測試,變成 #VALUE ,就用追蹤方式追查,才知道這行有問題。

手動改成 2 ^ i 就沒問題,好奇之下另外開個小專案測試:

誤使用到超長整數符號

誤使用到超長整數符號

用除錯模式看,型別居然是 LongLong 。

按下 F2 查物件類別庫,果然有 LongLong ,用 HEX(-1) 測試,是 8 bytes 的超長整數:

LongLong 為 8 bytes 超長整數

LongLong 為 8 bytes 超長整數

用 Google 搜尋 MSDN ,看起來是 x64 版本的 VBA 就加入了,應該是 Office 2010 x64 以後開始有此功能:
64 位元 Visual Basic for Applications 概觀:https://msdn.microsoft.com/zh-tw/library/office/Gg264421.aspx

順便回頭測了 Excel 2003 的 VBA 6.5:

Excel 2003 VBA 6.5 正確處理次方運算符號

Excel 2003 VBA 6.5 正確處理次方運算符號

舊版本的 VBA 就能自動把 2^2 轉成 2 ^ 2 。

從 LongLong 超長整數的 VBA 7.1 來看當初微軟在 2005 年宣告 VB6 不再支援的理由又消滅了一個,不是不能支援 64 bits 及加超長整數,而是不願意加,是不為也,非不能也。

Categories: 工作點滴, 技術分享 | 標籤: | 2 則迴響

[Office][bug]線上手冊越來越爛,這根本就又錯了嘛


話說,Office 2010 的 VBA 升級到 7.0 ,不禁讓我想到,2005/3 全球 Visual Basic 開發者在一個公開網站簽署,要求 VB6 要像 VC 一樣能被保留,弄成 VBNET 跟 B# 兩套,當時微軟的回應是窒礙難行…
事實上在 Office 2007 VB6 的核心 VBA 升級到 6.5 現在 Office 2010 VBA 達到 7.0 版,時間總能證明一切,這是微軟強制 VB6 開發者遷移到 VBNET 的手法而已。
這不是這篇的重點,話說我打開 VBA 線上手冊,要參考一些資訊時,忽然發現每個方法、屬性下面都多了一堆無意義的文字,那就是
文章
這樣非常占版面,找屬性變成需要猛翻頁,捲動滑鼠,檢視原始碼中,並沒有文章的 html 標籤跟內容,看樣子是某個白爛的 script 造成,我懷疑應該是原先要做到連結上的 title=’Document’ 被搞錯了,真是夠了。
經過檢查,Access、Excel、Outlook、PowerPoint、Publisher、Visio、Word ,都有這個情形,看來應該是共用說明文件就有這個 script 功能造成的。
Categories: Office | 標籤: | 發表留言

[VBA]自然人數位憑證簽名


今天收到經濟部工商憑證,就想說測試看看用公司的憑證簽程式碼,當然用 Excel VBA 來測試最方便,所以標題才會是 VBA ~
公司憑證很順利的完成程式碼數位簽章,想說,再測測看自然人憑證好了,以前自然人憑證簽不上去,所以重灌電腦後,自然人憑證沒有匯入電腦,這次新版的憑證匯入工具測看看。
一開始,我的憑證還是不能完成數位簽章,測娟娟的就可以正常完成數位簽章,不知道是不是我的憑證是第一代的,功能不全?
打電話到內政部的憑證管理中心電話詢問,邊做邊描述重現步驟時,忽然可以簽了… 汗…
回想一下,可能是我匯入我的自然人憑證時,Excel VBA 沒關,後來重開 Excel 就正常了。
若是不能用自然人憑證簽數位簽章的話,不妨到內政部憑證管理中心抓新版的軟體:
憑證匯入工具
MOICA_HiCOS_Setup
安裝HiCOS Clientv2.0.0.exe時,用戶不須另行下載安裝SafeSign CSP,即可於相關配合使用自然人憑證的應用軟體上具有資料加解密、認證安全的功能。
檔案下載
安裝程式若偵測到系統中已先裝有SafeSign程式時,本安裝軟體將協助解除安裝,使用者可不需自行移除SafeSign CSP程式。
※此軟體為Windows整合版本,支援Windows 98,Windows 2000,Windows XP,Windows Vista與Windows 2003。
zip 8.2 MB
在 Excel VBA 簽章過程中,內政部憑證跟一般證券、銀行、憑證認證中心的不太一樣,一般憑證選擇好就可以直接簽章,自然人憑證簽章時,必須插上讀卡機,簽章會跳出內政部的 PIN 碼輸入畫面,輸入完後,就可以正確完成簽章。
想要用自然人憑證簽章的,注意兩點:
1. 用新版的軟體匯入憑證。
2. 簽名時要插上讀卡機。
Categories: 技術分享 | 標籤: | 發表留言

Excel Variant Date 在 1900/3/1 以前的基準日與 VB6 不同


這個狀況更詳細的說明可以到 http://support.microsoft.com/ 搜尋 Excel 1900 。
簡單的說,最早的試算表 Lotus 123 把 1900 視為閏年,理論上來說,逢四閏、逢百不閏、逢四百閏,所以 1900 年為非閏年,但是在 Excel 會有 1900/2/29 的存在,當時的設計是為了與 Lotus 123 相容而存在,就用到現在,所以到了 Excel 2007 還是這樣…
Excel 有兩組日期系統,以 1900/1/0 為 基準或是 1904/1/1 為基準。下面是個簡表,Variant Date 為 OleAut32.dll 裡面定義的 Variant Date ,VB6/VBA/VBScript 的內建 Date 型態,VBNET 可用 ToOADate/FromOADate 轉換,核心值域是依據 IEEE 754 的 Double 來設計,所以加上 Double 的對照:
Double Variant Date Excel Date 1904 Date
0 1899/12/30 1900/1/0 1904/1/1
1 1899/12/31 1900/1/1 1904/1/2
2 1900/1/1 1900/1/2 1904/1/3
58 1900/2/26 1900/2/27 1904/2/28
59 1900/2/27 1900/2/28 1904/2/29
60 1900/2/28 1900/2/29 1904/3/1
61 1900/3/1 1900/3/1 1904/3/2
62 1900/3/2 1900/3/2 1904/3/3
Variant Date 在 1900/3/1 以後就完全與 Excel Date 重合,基本上不建議採用 1904 為基礎的日期資料。
可以看出來,Excel Date 居然有個 1900/1/0 ,算是很有趣的東西,此外,Excel 不接受基準日以前的日期,所以不能有 1899/12/31 這類的日期出現,當然,若採用 1904 為基準,就完全不會出現 1904 年以前的日期。
因此在 1900/3/1 以前的日期若仍要使用在 Excel 內,必須改用 VBA 來處理,並運用 String <-> Date 來相互轉換。
Categories: Office | 標籤: | 發表留言

[疑似Bug] VBA 的 SOAP


早上小跟小朱透過 Live Messenger 討論 Excel 2007 內呼叫 .Net 2.0 的 Web Service ,其中有一項引數為日期變數,要查詢某日的資料,但是小朱測試的結果是會傳回早一天,例如輸入 2007/3/2 會傳回 2007/3/1 。
因為我自己做氣象系統的關係,長期必須使用 UTC 時間,直覺上是時間問題,就建議測試 +8 小時來跑看看,因為 xml 內也是用 UTC 時間。
果然,小朱改用 +8 後就正常了。
不過我們懷疑這是 SOAP 的錯誤,因為這個應該在 SOAP 自動轉換內就完成,不應該讓使用者手動處理時區,所以就由小朱回報,若有後續結果由小朱通知後,再分享給大家參考。
Categories: 更新與回報 | 標籤: | 1 則迴響

替 VBA 簽上數位憑證


http://www.tlcheng.tk/TLCheng/Basic/vba/Signature/index.htm

最近常看到有人問到如何讓 VBA 所發展的程式不要一值跳出詢問盒,這個部分主要是 Office 2000 以後,鑒於巨集病毒太過氾濫,所建立的認證制度,所以以下的方法,均可使用在相同安全控管的軟體上。這些說明在 MSDN 中均可找到,我只整理我喜歡的慣用做法,當然有其他方法,不過個人喜好不同,你也可以自己試試。…

Categories: 電腦和網際網路 | 標籤: | 發表留言

在WordPress.com寫網誌.