Macro Converter 外掛程式會自動執行大部分的轉換程序,但您可能需要調整部分 API 和其他項目,才能完成程式碼。
本指南可協助您瞭解專案中加入的 Apps Script 檔案 (GS 檔案)、解讀各種錯誤類型,並瞭解如何修正錯誤。
瞭解新增至專案的 Apps Script 檔案
系統會在您的 Apps Script 專案中加入額外的 GS 檔案,藉此提供以下協助:
- 定義 Apps Script 中沒有的 VBA 常數和值。
- 實作未轉換的 API。
- 解決變化版本。
系統會將下列 GS 檔案新增至 Apps Script 專案:
Library.gs
Unimplemented_constructs.gs
Variant_resolutions.gs
Library.gs
一般來說,您不需要修改 library.gs
檔案中的任何內容。
library.gs
檔案定義了 VBA 程式碼中使用的函式和常數,但不適用於 Apps Script。如此一來,新的 Apps Script 程式碼就會與 VBA 程式碼更相似。此外,您不需要在每次使用 library.gs
檔案中的函式或常數時重複定義。
Unimplemented_constructs.gs
unimplemented_constructs.gs
檔案位址的建構或 API 無法由 Macro 轉換器轉換。您可能需要修改這個檔案,程式碼才能正常運作。
範例:Window.Activate()
以下為不支援 Window.Activate()
的 API 範例。巨集轉換器會以類似的名稱建立新的 Apps Script 函式,並在 unimplemented_constructs.gs
檔案中定義該函式。由於系統不支援 VBA 函式,因此新的 Apps Script 函式會擲回例外狀況。
新函式會加入轉換後的 Apps Script 程式碼中,所有在 VBA 程式碼中使用原始 API 的地方。
如果您找到重新建立原始 API 行為的解決方法,則只需要更新 unimplemented_constructs.gs
檔案中的函式定義。定義函式之後,該函式就會套用至 Apps Script 專案中顯示的所有位置。
程式碼範例中的範例如下:
原始 VBA 代碼
Window.activate()
已轉換的 Apps Script 程式碼 (已自動新增)
_api_window_activate();
函式定義已新增至 unimplemented_constructs.gs
檔案
/** * Could not convert window.activate API. Please add relevant code in the * following function to implement it. * This API has been used at the following locations in the VBA script. * module1 : line 3 * * We couldn't find an equivalent API in Apps Script for this VBA API. Please * reconsider if this function call is critical, otherwise consider implementing * it in a different way. */ function _api_window_activate(CallingObject) { ThrowException("API window.activate not supported yet."); }
Variant_resolutions.gs
如果無法判斷物件的類型,系統會將 variant_resolutions.gs
檔案新增至您的 Apps Script 專案。發生這種情況的原因很多,例如 API 具有多種傳回類型,或者將物件宣告為變化版本。
Macro Converter 會在這個檔案中加入名為 __handle_resolve_<api>()
的函式,取代相關 API,並協助判斷物件類型。
在某些情況下,您可能需要更新 __handle_resolve_<api>()
函式,手動宣告物件類型。詳情請參閱「不支援的物件類型」一節。
範例:name()
VBA 中的許多物件類型都定義了 name()
API。通常,Apps Script 等同於 getName()
,但並非所有物件類型都能使用。可能會發生多種替代情況:
- 物件的對等 API 稱為
getName()
不同的名稱。 - 物件沒有 Apps Script API,因此無法取得其名稱。
- 沒有對等的 Apps Script 物件。
如未判斷物件類型,Macro 轉換工具會在 variant_resolutions.gs
檔案中建立名為 __handle_resolve_name
的新函式。
程式碼範例中的範例如下:
原始 VBA 代碼
a = Selection.name
在本範例中,系統會在目前選取項目中呼叫 API name()
。選取項目可以是工作表物件或形狀物件。如果是工作表物件,平移為 getName()
,但如果是 Shape 物件,表示 Apps Script 中沒有同等的翻譯。
已轉換的 Apps Script 程式碼 (已自動新增)
a = __handle_resolve_name({}, getActiveSelection(), {});
下列 __handle_resolve_name()
函式會新增至 variant_resolution.gs
檔案,以便解決不同的物件類型。函式會檢查物件類型,如果支援的話就會使用 getName()
;如果不支援 getName()
,則會擲回錯誤。
函式定義已新增至 variant_resolution.gs
檔案
function __handle_resolve_name(ExecutionContext, CallingObject, params_map) { var found_api_variant = false; var return_value; if (String(CallingObject) == "Sheet") { if (!ExecutionContext.isLhs) { return_value = CallingObject.getName(); found_api_variant = true; } } if (CallingObject instanceof ChartInSheet) { if (!ExecutionContext.isLhs) { return_value = CallingObject.getName(); found_api_variant = true; } } if (!found_api_variant) { ThrowException("API.name not supported yet."); } return return_value; }
找出錯誤
如果您在轉換的 Apps Script 程式碼中發生錯誤,訊息會指出錯誤類型及其位置。錯誤訊息的格式取決於您使用的 Apps Script 執行階段。
如果使用的是預設的 V8 執行階段,您會看到如下所示的錯誤:
_api_windows_active (unimplemented_constructs:2:3)
這表示錯誤位於第 2 行第 3 行的 unimplemented_constructs.gs
檔案中。
如果您在已淘汰的 Rhino 執行階段中,系統會顯示如下所示的錯誤:
unimplemented_constructs:2 (_api_windows_active)
這表示錯誤位於第 2 行的 unimplemented_constructs.gs
檔案中。
錯誤類型
您可以修正上述 unimplemented_constructs.gs
和 variant_resolution.gs
檔案中發生的大多數錯誤。
可能出現的錯誤類型包括:
未導入的 API
未實作的 API 是 Macro Converter 無法從 VBA 轉換為 Apps Script 的 API,而且該 API 沒有已知的解決方法。
未實作的 API 通常會以空白函式的形式 (有時含有空白簽名) 加入 unimplemented_constructs.gs
檔案。如果無法判斷物件類型,系統可能會改為將未實作的 API 新增至 variant_resolution.gs
檔案。
在轉換前產生的相容性報表中,這個 API 會標示為「需要進一步調查」。
如果在轉換檔案前,您未在 VBA 程式碼中修正這類 API,以下是該檔案在 Apps Script 專案中的顯示方式:
/** * Could not convert. Please add relevant code in the following * function to implement it. * This API has been used at the following locations in the VBA script. * : * We couldn't find an equivalent API in Apps Script for this VBA API. Please * reconsider if this function call is critical, otherwise consider implementing * it in a different way. * @param param1 { } * @param param2 { } * ... * @return { } */ function _api_ (param1, param2, ....) { ThrowException("API not supported yet."); }
修正未導入的 API 錯誤
使用現有的 Apps Script API 或 JS 程式庫定義未實作的 API。 步驟如下:
- 請在發生錯誤的位置開啟轉換後的 Apps Script 程式碼。請參閱「找出錯誤」一文。
- 在函式上方讀取新增了的註解。在某些情況下,註解會建議如何在 Apps Script 中實作 API。
- 如果您找不到在 Apps Script 中實作 API 的方法,請考慮從程式碼中移除 API。
- 如果您在程式碼中找不到解決方法或移除這個 API,且巨集擲回此錯誤,您就無法轉換這個巨集。
未導入 API 錯誤的示例
以下列出尚未實作的 API 情境和解決方法:
- 沒有對等的 Apps Script:顯示
Chart.Protect
的間接解決方法,這個 API 不存在於 Apps Script 中。 - 不明物件類型:說明如何處理變數的物件類型,以及如何實作不支援的物件類型 (可在 Apps Script 中重新建立)。
範例 1:沒有對等的 Apps Script 或不明 API
在此範例中,由於 Google 試算表中無法保護圖表,因此系統不會自動轉換 Chart.Protect
。
/** * Could not convert chart.protect API. Please add relevant code in the following * function to implement it. * * This API has been used at the following locations in the VBA script. * sheet1 : line 3 * You can use the following Apps Script APIs to convert it. * * Comments : Auto conversion of Chart.Protect is not supported yet. If the API is * critical for the workflow the user can implement the unimplemented handler * method in the generated code, else comment out the throw statement. * * @param {Object} CallingObject represents the parent object using which the API * has been called. * @param {string} Password * @param {boolean} DrawingObjects * @param {boolean} Contents * @param {boolean} Scenarios * @param {boolean} UserInterfaceOnly * */ function _api_chart_protect( CallingObject, Password, DrawingObjects, Contents, Scenarios, UserInterfaceOnly) { ThrowException('API chart.protect not supported yet.'); }
以下提供一個保護範圍的實作範例:
/** * Could not convert chart.protect API. Please add relevant code in the following * function to implement it. * This API has been used at the following locations in the VBA script. * sheet1 : line 3 * * You can use the following Apps Script APIs to convert it. * Comments : Auto conversion of Chart.Protect is not supported yet. If the API * is critical for the workflow the user can implement the unimplemented handler * method in the generated code, else comment out the throw statement. * * @param {Object} CallingObject represents the parent object using which the API * has been called. * @param {string} Password * @param {boolean} DrawingObjects * @param {boolean} Contents * @param {boolean} Scenarios * @param {boolean} UserInterfaceOnly */ function _api_chart_protect( CallingObject, Password, DrawingObjects, Contents, Scenarios, UserInterfaceOnly) { var ranges = CallingObject.getChart().getRanges(); for (var i = 0; i < ranges.length; i++) { // Note that this does not lock the range for the document owner. ranges[i].protect(); } }
範例 2:不支援的物件類型
當物件類型不明時,系統會將未實作的 API 錯誤加入 variant_resolution.gs
檔案。下列範例根據上述 VBA name()
API 範例展開。請參閱「variant_resolution.gs
」。
這個範例會說明:
name()
API 如何轉換為variant_resolution.gs
檔案中的新函式。- 如何在轉換後的程式碼呼叫新函式。
- 如何在 Apps Script 中為
CommandBar
(不支援的物件類型) 建立解決方法。
1. 由於轉換的程式碼無法判斷呼叫 name()
的確切物件類型,因此巨集轉換器會建立名為 __handle_resolve_name
的新函式,如下所示。
function __handle_resolve_name(ExecutionContext, CallingObject, params_map) { var found_api_variant = false; var return_value; if (String(CallingObject) == "Sheet") { if (!ExecutionContext.isLhs) { return_value = CallingObject.getName(); found_api_variant = true; } } if (CallingObject instanceof ChartInSheet) { if (!ExecutionContext.isLhs) { return_value = CallingObject.getName(); found_api_variant = true; } } if (!found_api_variant) { ThrowException('API.name not supported yet.'); } return return_value; }
2. 假設 VBA 程式碼定義了呼叫 name()
API 的 PrintName()
函式。VBA 代碼如下所示:
‘Defining a function that prints the name of the object in parameter Sub PrintName(obj as Variant) Debug.Print obj.Name End Sub由於系統是透過變數物件呼叫「name()」,因此轉換的程式碼並不知道轉換時的物件類型。轉換後的 Apps 指令碼程式碼將呼叫「__handle_resolve_name」函式:
function PrintName(obj) { Logger.log(_handle_resolve_name(obj)); }
3. 假設 VBA 程式碼對物件類型 CommandBar
呼叫 PrintName()
函式。VBA 代碼如下所示:
PrintName Application.CommandBars.item("Standard")
CommandBar
,因此上述 VBA 程式碼也不支援使用這兩種方法。Application.CommandBars()
:在 VBA 中,這樣做會傳回所有CommandBar
物件的清單。CommandBars.item()
:在 VBA 中,這會傳回特定的CommandBar
物件。
_api_application_commandbars()
_api_commandbars_item()
PrintName(_api_commandbars_item(_api_application_commandbars(), "Standard"))) Here’s how the new functions are added to the unimplemented_construct.gs file: function _api_application_commandbars(CallingObject) { ThrowException('API application.commandbars not supported yet.'); } function _api_commandbars_item(CallingObject, index) { ThrowException('API commandbars.item not supported yet.'); }
如要讓新函式正常運作,請按照下列步驟操作:
3.1 定義新的物件類型,該類型會建立 CommandBars
的功能和新的 CommandBars
集合,類似於 VBA 中的現有項目。
3.2 為新的物件類型新增 getName()
方法。
步驟 3.1 和 3.2 如以下程式碼所示。選單物件會建立為新的物件類型,可模仿 CommandBars
的行為。
// Our Implementation of CommandBar using Menu objects. function CommandBar(name) { this.name = name; // Create a menu object to represent the commandbar. this.menu = SpreadsheetApp.getUi().createMenu(name); // Create methods for retrieving or updating the name of the object this.getName = function() { return this.name; }; this.updateName = function(name) { this.name = name; }; // ======================================================================== // Implement other methods of CommandBar objects that are used in the script. // ===================================================================== return this; } // Our implementation of the collection of CommandBars that exists in VBA function CommandBars() { this.commandBars = []; this.getCommandBar = function(name) { for (var i = 0; i < this.commandBars.length; i++) { if (!this.commandBars[i].getName() == name) { return this.commandBars[i]; } } // No commandBar with the name exists, create a new one and return. var commandBar = new CommandBar(name); this.commandBars.push(commandBar); return commandBar; }; return this; } // Create a global object that represents CommandBars collection. var GlobalCommandBars = new CommandBars();
3.3 修改 variant_resolution.gs
檔案中的 __handle_resolve_name
函式來處理新的物件類型。在函式中新增區段,如下所示:
function __handle_resolve_name(ExecutionContext, CallingObject, params_map) { var found_api_variant = false; var return_value; if (String(CallingObject) == "Sheet") { if (!ExecutionContext.isLhs) { return_value = CallingObject.getName(); found_api_variant = true; } } if (CallingObject instanceof ChartInSheet) { if (!ExecutionContext.isLhs) { return_value = CallingObject.getName(); found_api_variant = true; } } // New section added below // ======================================================================== if (CallingObject instanceof CommandBar) { objectExtend(params_map, {VALUETOSET: params_map.param0}); if (ExecutionContext.isLhs) { // Call the setter method. CallingObject.updateName(params_map.VALUETOSET); found_api_variant = true; } else { // Getter is called, return the commandbar name, return_value = CallingObject.getName(); found_api_variant = true; } } // ======================================================================== // New section added above if (!found_api_variant) { ThrowException('API.name not supported yet.'); } return return_value; }
3.4 定義在 unimplemented_constructs.gs
檔案 (_api_application_commandbars()
、_api_commandbars_item()
) 中建立的兩個函式。這個步驟可確保函式的原始呼叫有效。
//This is straightforward based on the implementation of a CommandBar and the // CommandBars collection above: function _api_application_commandbars(CallingObject) { return GlobalCommandBars; } function _api_commandbars_item(CallingObject, index) { return CallingObject.getCommandBar(index); }
未實作的語言結構
construct是程式碼語言的元素,用於控制執行流程或資料顯示。例如迴圈、標籤、事件和取得。詳情請參閱所有 VBA 建構項目清單。
巨集轉換器無法轉換的建構視為「未實作的語言結構」。
當 Macro 轉換工具判定尚未實作的語言結構存在時,會插入 TODO
註解。
系統不支援下列 VBA 建構項目:
修正未實作的語言建構錯誤
- 請更新程式碼,讓邏輯不會仰賴不支援的語言結構。
- 請在發生錯誤的位置開啟轉換後的 Apps Script 程式碼。請參閱「尋找錯誤」一節。
- 根據程式碼邏輯,更新方式無需使用不支援的語言建構。
- 如果在未使用不支援的語言結構的情況下,找不到重新編寫程式碼的方法,則無法轉換這個巨集。
未實作語言建構錯誤的示例
最常見的未實作語言結構之一是 GoTo
陳述式。您可以將部分 VBA GoTo
陳述式替換為迴圈。以下是兩個使用迴圈而非 GoTo
陳述式的範例。
範例 1:將 GoTo
替換成 While Loop
原始 VBA 代碼Sub Test() a = 0 start: Debug.Print a While a < 100 a = a + 1 If a Mod 3 == 0 Goto start End If Wend End Sub
function test() { var a = 0; start: do { console.log(a); while (a < 100) { a = a + 1; if (a % 3 == 0) { continue start; } } break start; } while (true); }
範例 2:將 GoTo 替換為迴圈
原始 VBA 代碼Sub Test() a = 0 For i = 1 to 100 For j = 1 to 10 a =a a + 1 If i + j > 50 GoTo endLoop End If Next j Next i endLoop: MsgBox a End Sub
function test() { var a = 0; endLoop: for (var i = 1; i <= 100; i++) { for (var j = 0; j <=10; j++) { If (i + j > 50) { break endLoop; } } } Browser.msgBox(a); } break start; } while (true); }
部分支援的 API
針對部分支援的 API,Apps Script 支援部分輸入參數,某些輸入參數則不支援。
舉例來說,VBA API legend_position
的作用是在 Excel 圖表中定義圖例。支援多種輸入值,包括:
xlLegendPositionBottom
:將圖例放在圖表底部。xlLegendPositionCorner
:將圖例放在圖表的角落。xlLegendPositionCustom
:將圖例放在圖表上的自訂位置。
Apps Script 的同等程式碼僅支援部分值。不支援下列值:
xlLegendPositionCorner
xlLegendPositionCustom
如要在轉換的程式碼中標記部分支援 API 不支援的值,系統會在 library.gs
檔案中加入驗證條件,以便檢查這些值。範例如下:
if (position == xlLegendPositionCorner || position == xlLegendPositionCustom) { position = _handle_legend_position_error(position); }
如果驗證條件找到其中一個不支援的值,就會在 unimplemented_constructs.gs
檔案中建立錯誤處理常式函式 _handle_<API_name>_error
。
這個函式會擲回使用者錯誤,不會將該值替換為支援的值。例如:
/** * Throw error message for unsupported legend position. * The VBA API Legend.Position which can take values xlLegendPositionTop, * xlLegendPositionLeft, xlLegendPositionBottom, xlLegendPositionRight, * xlLegendPositionCorner, xlLegendPositionCustom. It is partially supported in * Apps Scripts that supports only a subset of the values (does not support * xlLegendPositionCorner and xlLegendPositionCustom). * @param {string} position */ function _handle_legend_position_error(position) { // Please comment the throw statement and return a supported position value // instead. // Values that are supported here are xlLegendPositionTop, // xlLegendPositionLeft, xlLegendPositionBottom, xlLegendPositionRight. throw new Error( 'Google Sheets does not support legend position: ' + position); }
修正部分支援的 API 錯誤
請定義 _handle_<API_name>_error
函式,將不支援的值替換為可接受的解決方法。
- 請在發生錯誤的位置開啟轉換後的 Apps Script 程式碼。請參閱「找出錯誤」一文。
- 請詳閱函式上方的註解,瞭解支援及排除的值。
- 針對不支援的值,判斷哪些支援的值可做為適當的替換值。
- 更新
_handle_<API_name>_error
函式,改為傳回支援的值。 - 如果找不到取代不支援值的方法,就無法轉換這個巨集。
部分支援的 API 錯誤示例
以下範例以上述 VBA API legend_position
為基礎進一步擴充。請參閱部分支援的 API。
以下範例是原始 VBA 程式碼使用不支援的值 xlLegendPositionCustom
。
Charts(1).Legend.Position = xlLegendPositionCustom
巨集轉換器會在 unimplemented_constructs.gs
檔案中加入下列函式:
/** * Throw error message for unsupported legend position. * The VBA API Legend.Position which can take values xlLegendPositionTop, * xlLegendPositionLeft, xlLegendPositionBottom, xlLegendPositionRight, * xlLegendPositionCorner, xlLegendPositionCustom. It is partially supported in * Apps Scripts that supports only a subset of the values (does not support * xlLegendPositionCorner and xlLegendPositionCustom). * @param {string} position */ function _handle_legend_position_error(position) { // Please comment the throw statement and return a supported position value // instead. // Values that are supported here are xlLegendPositionTop, // xlLegendPositionLeft, xlLegendPositionBottom, xlLegendPositionRight. throw new Error( 'Google Sheets does not support legend position: ' + position); }
需要人工作業
「需要手動作業」表示 VBA API 可以轉換為 Apps Script,但需要替代方案。
在轉換前產生的相容性報表中,這個 API 會標示為「支援變通方案」。
如果在轉換檔案前,您未在 VBA 程式碼中修正這類 API,以下是該檔案在 Apps Script 專案中的顯示方式:
/** * Could not convertAPI. Please add relevant code in the following * function to implement it. * This API has been used at the following locations in the VBA script. * : * * You can use the following Apps Script APIs to convert it. * Apps Script APIs : * Apps Script documentation links : * * @param param1 { } * @param param2 { } * ... * @return { } */ function _api_ (param1, param2, ....) { ThrowException("API not supported yet."); }
修正需要人工作業的錯誤
實作解決方法,讓 API 能正常運作。 1. 請在發生錯誤的位置開啟轉換後的 Apps Script 程式碼。請參閱「找出錯誤」一文。1. 請詳閱函式上方的註解,瞭解哪些 API 可用來解決問題。1. 如果您找不到適當的解決方法,請考慮從程式碼中移除 API。1. 如果找不到解決方法,或是從程式碼中移除這個 API,且巨集會擲回錯誤,您就無法轉換這個巨集。
需要錯誤的人工作業示例
以下列舉幾個會擲回手動工作需要錯誤的 API 範例,以及這類錯誤的修正方式:
Implement a workaround for Autocorrect.Addreplacement
.Implement a workaround for workbook.open()
。這個範例說明如何使用 Apps Script 開啟 Google 雲端硬碟中的檔案。
範例 1:Autocorrect.Addreplacement
在以下範例中,可以轉換 VBA API Autocorrect.Addreplacement
,但需要解決方法。巨集轉換器建議如何在程式碼註解中實作函式。
/** * Could not convert autocorrect.addreplacement API. Please add relevant code in * the following function to implement it. * This API has been used at the following locations in the VBA script. * sheet1 : line 3 * You can use the following Apps Script APIs to convert it. * Apps Script APIs : FindReplaceRequest , onEdit * Apps Script documentation links : * https://developers.google.com/apps-script/reference/script/spreadsheet-trigger-builder#onedit * https://developers.google.com/sheets/api/eap/reference/rest/v4/spreadsheets/request?hl=en#findreplacerequest * Comments : AutoCorrect.AddReplacement was not converted, but there is an * equivalent option you can implement manually. Use onEdit and FindReplaceRequest * APIs instead, see https://developers.google.com/apps-script/reference/script/spreadsheet-trigger-builder#onedit * and https://developers.google.com/sheets/api/eap/reference/rest/v4/spreadsheets/request?hl=en#findreplacerequest. * For more information on API manual implementation, see * https://developers.google.com/apps-script/guides/macro-converter/fix-conversion-errors. * @param {Object} CallingObject represents the parent object using which the API * has been called. * @param {string} What * @param {string} Replacement * @return {string} */ function _api_autocorrect_addreplacement(CallingObject, What, Replacement) { ThrowException('API autocorrect.addreplacement not supported yet.'); }
Autocorrect.Addreplacement
API 的實作方式如下所示:
var AUTO_CORRECTIONS = "AUTO_CORRECTIONS"; // Need to get the autocorrections set in previous sessions and use them. var savedAutoCorrections = PropertiesService.getDocumentProperties().getProperty(AUTO_CORRECTIONS); var autoCorrections = savedAutoCorrections ? JSON.parse(savedAutoCorrections) : {}; function onEdit(e) { autoCorrect(e.range); } function autoCorrect(range) { for (key in autoCorrections) { // Replace each word that needs to be auto-corrected with their replacements. range.createTextFinder(key) .matchCase(true) .matchEntireCell(false) .matchFormulaText(false) .useRegularExpression(false) .replaceAllWith(autoCorrections[key]); } } /** * Could not convert autocorrect.addreplacement API. Please add relevant code in * the following function to implement it. * This API has been used at the following locations in the VBA script. * sheet1 : line 3 * * You can use the following Apps Script APIs to convert it. * Apps Script APIs : createTextFinder , onEdit * Apps Script documentation links : https://developers.google.com/apps-script/reference/script/spreadsheet-trigger-builder#onedit , createTextFinder * Comments : AutoCorrect.AddReplacement was not converted, but there is an * equivalent option you can implement manually. Use onEdit and FindReplaceRequest * APIs instead, see https://developers.google.com/apps-script/reference/script/spreadsheet-trigger-builder#onedit * and createTextFinder. For more information on API manual implementation, see * https://developers.google.com/apps-script/guides/macro-converter/fix-conversion-errors. * * @param {Object} CallingObject represents the parent object using which the API has been called. * @param {string} What * @param {string} Replacement * * @return {string} */ function _api_autocorrect_addreplacement(CallingObject, What, Replacement) { autoCorrections[What] = Replacement; // Store the updated autoCorrections in the properties so that future executions use the correction. PropertiesService.getDocumentProperties().setProperty(AUTO_CORRECTIONS, JSON.stringify(autoCorrections)); }
範例 2:Workbook.open()
VBA API workbook.open()
會根據檔案路徑開啟本機檔案。
假設 workbook.open()
在 VBA 程式碼中開啟了兩個檔案:
- 檔案 1:
C:\Data\abc.xlsx
- 檔案 2:
C:\Data\xyz.xlsx
以下說明 Macro Converter 如何在所有 Workbook.open()
用來開啟檔案 1 的地方,將 Workbook.open()
替換為 Apps Script:
var spreadSheetId = _handle_mso_excel_get_google_spreadsheet_id("C:\Data\abc.xlsx"); var spreadSheet = SpreadsheetApp.openById(spreadSheetId);
unimplemented_constructs.gs
檔案中加入以下錯誤:
/** * Method to return the spreadsheet id manually. * * @param {string} FileName ID of the spreadsheet to be opened. * @return {string} return the spreadsheet id. */ function _handle_mso_excel_get_google_spreadsheet_id(FileName) { // Upload the Excel files being opened by the API to Google Drive and convert // them to Google Sheets. // Determine the spreadsheet ID of the Google Sheets file created. // Implement this method to return the corresponding spreadsheet ID when given //the original file path as parameter. throw new Error('Please return the spreadsheet ID corresponding to filename: ' + FileName); return ''; }
根據上述範例中的註解指示,您必須將目標檔案轉換為 Google 雲端硬碟中的 Google 試算表檔案。
對應的 Google 試算表 ID 會以粗體顯示:
- 檔案 #1:
C:\Data\abc.xlsx
變成https://docs.google.com/spreadsheets/d/abc123Abc123Abc123abc
- 檔案 #2:
C:\Data\abc.xlsx
變成https://docs.google.com/spreadsheets/d/xyz456Xyz456xYz456xyZ
接著,修改 Apps Script 函式中的程式碼,以 ID 開啟檔案,如下所示:
/** * Method to return the spreadsheet id manually. * * @param {string} FileName ID of the spreadsheet to be opened. * @return {string} return the spreadsheet id. */ function _handle_mso_excel_get_google_spreadsheet_id(FileName) { // Upload the Excel files being opened by the API to Google Drive and convert //them to Google Sheets. // Determine the spreadsheet ID of the Google Sheets file created. // Implement this method to return the corresponding spreadsheet ID when given //the original file path as parameter if (Filename.indexOf("abc.xlsx") >= 0) { return "abc123Abc123Abc123abc"; } else if (Filename.indexOf("xyz.xlsx") >= 0) { return "xyz456Xyz456xYz456xyZ"; }
刻意錯誤
轉換的程式碼會加入意圖錯誤,以模仿原始 VBA 程式碼的錯誤行為。您不需要修改這些錯誤。
意圖錯誤示例
如果您嘗試存取超過 VBA 陣列邊界以外的元素,程式碼會擲回例外狀況。Apps Script 中的程式碼會傳回未定義。
為避免發生非預期的結果,Macro Converter 會新增 Apps Script 程式碼。當您嘗試存取陣列邊界以外的元素時,此程式碼會擲回例外狀況。
如以下程式碼所示:
原始 VBA 代碼Dim arr arr = Array("apple", "orange") MsgBox arr(5) Will throw the following error: Subscript out of range
var arr; arr = ["apple", "orange"]; Browser.msgBox(arr[5]); Will return this value and not throw an error: undefined
/** * Extend the regular JS array to support VB style indexing with a get method. * @returns{*} value at the index */ Array.prototype.get = function() { var curr_res = this; for (var i = 0; i < arguments.length; i++) { if (!Array.isArray(curr_res) || curr_res.length < arguments[i]) { throw new Error(‘Converted VBA Error (Intentional Error): Subscript out of range’); } curr_res = curr_res[arguments[i]]; } return curr_res; }; var arr; arr = ["apple", "orange"]; Browser.msgBox(arr.get(5));