Macro Converter 插件可自动完成大部分转换过程,但您可能需要对某些 API 和其他项进行调整,以最终完成代码。
借助本指南,您可以了解添加到项目的 Apps 脚本文件 (GS 文件),解读不同的错误类型,并了解如何修正错误。
了解添加到您项目中的 Apps 脚本文件
您的 Apps 脚本项目中添加了其他 GS 文件,以帮助:
- 定义 Apps 脚本中不存在的 VBA 常量和值。
- 实现未转换的 API。
- 解析变体。
以下 GS 文件会添加到您的 Apps 脚本项目中:
Library.gs
Unimplemented_constructs.gs
Variant_resolutions.gs
Library.gs
通常,您无需修改 library.gs
文件中的任何内容。
library.gs
文件定义了在 VBA 代码中使用但 Apps 脚本中不存在的函数和常量。这有助于新的 Apps 脚本代码更接近您的 VBA 代码。此外,您无需在每次使用 library.gs
文件中的函数或常量时都重复定义。
Unimplemented_constructs.gs
unimplemented_constructs.gs
文件会处理宏转换器无法转换的构造或 API。您可能需要修改此文件,才能使代码按预期运行。
示例:Window.Activate()
以下是不受支持的 API 示例,名为 Window.Activate()
。Macro Converter 会创建一个具有类似名称的新 Apps 脚本函数,并在 unimplemented_constructs.gs
文件中对其进行定义。由于 VBA 函数不受支持,新的 Apps 脚本函数会抛出异常。
新函数会添加到转换后的 Apps 脚本代码中,在 VBA 代码中使用原始 API 的所有位置。
如果您找到重现原始 API 行为的权宜解决方法,只需在 unimplemented_constructs.gs
文件中更新函数定义即可。在此处定义函数后,该函数将应用于 Apps 脚本项目中的所有位置。
以下是代码中的示例:
原始 VBA 代码
Window.activate()
已转换的 Apps 脚本代码(内嵌添加)
_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 脚本项目中。发生这种������的原���有很多,例如 API 具有多个返回类型,或者对象本身被声明为变体。
Macro Converter 会在此文件中添加一个名为 __handle_resolve_<api>()
的新函数,该函数替换了相关 API 并帮助确定对象类型。
在某些情况下,您可能需要更新 __handle_resolve_<api>()
函数以手动声明对象类型。请参阅不支持的对象类型。
示例:name()
VBA 中的许多对象类型都定义了 name()
API。通常,Apps 脚本的等效项为 getName()
,但并非适用于所有对象类型。可能会发生多种备选情况:
- 该对象的等效 API 的名称与
getName()
不同。 - 该对象没有用于获取其名称的 Apps Script API。
- 没有等效的 Apps 脚本对象。
如果未确定对象类型,宏转换器会在 variant_resolutions.gs
文件中创建一个名为 __handle_resolve_name
的新函数。
以下是代码中的示例:
原始 VBA 代码
a = Selection.name
在这种情况下,系统会针对当前选择调用 API name()
。所选项可以是工作表对象或 Shape 对象。如果是 Google 表格对象,则转换为 getName()
,但对于 Shape 对象,在 Apps 脚本中没有等效项。
已转换的 Apps 脚本代码(内嵌添加)
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 脚本代码中遇到错误时,该消息会指明错误类型及其位置。错误消息的格式取决于您使用的 Apps 脚本运行时。
如果您使用的是默认 V8 运行时,您将看到如下所示的错误:
_api_windows_active (unimplemented_constructs:2:3)
这意味着错误位于 unimplemented_constructs.gs
文件中的第 2 行第 3 个字符。
如果您使用的是已废弃的 Rhino 运行时,则会看到如下所示的错误:
unimplemented_constructs:2 (_api_windows_active)
这意味着错误位于 unimplemented_constructs.gs
文件的第 2 行。
错误类型
您可以修复在上述 unimplemented_constructs.gs
和 variant_resolution.gs
文件中遇到的大多数错误。
您可能会遇到的错误类型包括:
未实现的 API
未实现的 API 是指宏转换器无法从 VBA 转换为 Apps 脚本的 API,并且没有针对该 API 的已知解决方法。
未实现的 API 通常会作为空函数(有时带有空签名)添加到 unimplemented_constructs.gs
文件中。如果无法确定对象类型,可能会改为将未实现的 API 添加到 variant_resolution.gs
文件中。
在转换前生成的兼容性报告中,此 API 标记为需要更多调查。
如果您在转换文件之前没有在 VBA 代码中修复此类 API,那么它在 Apps 脚本项目中的显示方式如下:
/** * 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 脚本代码。请参阅查找错误。
- 在函数上方,阅读添加的注释。在某些情况下,注释会建议如何在 Apps 脚本中实现 API。
- 如果您无法找到在 Apps 脚本中实现该 API 的方法,请考虑从您的代码中移除该 API。
- 如果您找不到解决方法或从您的代码中移除此 API,并且您的宏抛出了此错误,那么您将无法转换此宏。
未实现的 API 错误示例
以下是未实现的 API 场景的示例以及如何解决这些问题:
- 没有等效的 Apps 脚本:显示了
Chart.Protect
的间接解决方法,这是 Apps 脚本中不存在的 API。 - 未知对象类型:展示如何处理属于变量的对象类型,以及如何实现可以在 Apps 脚本中重新创建的不受支持的对象类型。
示例 1:没有等效的 Apps 脚本或未知 API
在此示例中,系统不会自动转换 Chart.Protect
,因为 Google 表格中没有保护图表的方法。
/** * 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 脚本中为
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
功能的新对象类型,以及类似于 VBA 中存在的新的 CommandBars
集合。
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是代码语言中的一个元素,用于控制执行流或数据显示。例如,循环、标签、事件和 Gotos。 以下是所有 VBA 结构的列表。
宏转换器无法转换的结构被视为未实现的语言结构。
如果宏转换器确定存在未实现的语言结构,则会插入 TODO
注释。
不支持以下 VBA 结构:
修复未实现的语言构造错误
- 请更新您的代码,确保您的逻辑不依赖于不受支持的语言结构。
- 在出现错误的位置,打开已转换的 Apps 脚本代码。请参阅查找错误。
- 根据代码逻辑,以不需要不受支持的语言结构的方式进行更新。
- 在没有不受支持的语言结构的情况下,如果您找不到重写代码的方法,则无法转换此宏。
未实现的语言构造错误示例
最常见的未实现语言结构之一是 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 替换为 For 循环
原始 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 脚本中受支持,有些则不受支持。
例如,VBA API legend_position
用于定义 Excel 图表中的图例。它支持多种类型的输入值,包括:
xlLegendPositionBottom
:将图例置于图表底部。xlLegendPositionCorner
:将图例置于图表一角。xlLegendPositionCustom
:将图例放在图表上的自定义位置。
Apps 脚本的等效代码仅支持其中部分值。不支持以下值:
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 脚本代码。请参阅查找错误。
- 请阅读函数上方的注释,了解哪些值受支持,哪些值不受支持。
- 对于不支持的值,请确定哪些支持的值可以作为合适的替换值。
- 请更新函数
_handle_<API_name>_error
以改为返回支持的值。 - 如果您无法找到替换不受支持的值的方法,则无法转换此宏。
部分支持的 API 错误示例
以下示例扩展了上述 VBA API legend_position
。请参阅部分支持的 API。
以下是使用不受支持的值 xlLegendPositionCustom
的原始 VBA 代码示例。
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 脚本,但需要解决方法。
在转换前生成的兼容性报告中,此类 API 会标记为受支持,但有变通解决方法。
如果您在转换文件之前没有在 VBA 代码中修复此类 API,那么它在 Apps 脚本项目中的显示方式如下:
/** * 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 实现解决方法,以使 API 按预期运行。 1. 在出现错误的位置,打开已转换的 Apps 脚本代码。请参阅查找错误。 1. 请参阅函数上方的注释,了解哪些 API 可用于权宜解决方法。 1. 如果找不到合适的权宜解决方法,请考虑从您的代码中移除该 API。 1. 如果您无法找到解决方法或从您的代码中移除此 API,并且您的宏抛出错误,则无法转换此宏。
“需要手动完成的工作”错误示例
以下是抛出“需要手动工作”错误的 API 示例以及解决方法:
Implement a workaround for Autocorrect.Addreplacement
.Implement a workaround for workbook.open()
。此示例展示了如何使用 Apps 脚本打开 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()
会根据文件路径打开本地文件。
假设 VBA 代码中的 workbook.open()
正在打开两个文件:
- 文件 1:
C:\Data\abc.xlsx
- 文件 2:
C:\Data\xyz.xlsx
下面显示了���转换器如何在使用 Workbook.open()
打开文件 1 的所有位置将 Workbook.open()
替换为 Apps 脚本:
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 脚本函数中的代码,按 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 脚本中,代码会返回未定义。
为避免出现意外结果,Macro Converter 添加了 Apps 脚本代码,当您尝试访问数组边界以外的元素时,该代码会抛出异常。
该示例如以下代码所示:
原始 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));