修正转换后代码中的错误

宏转换器插件可自动执行大部分转换流程,但您可能需要调整一些 API 和其他项才能最终完成代码。

请使用本指南了解添加到项目中的 Apps 脚本文件(GS 文件),解读不同的错误类型,并了解如何修复错误。

了解添加到项目中的 Apps 脚本文件

其他 GS 文件已添加到您的 Apps 脚本项目中,以帮助您:

  • 定义 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 文件用于处理 Macro Converter 无法转换的构造或 API。您可能需要修改此文件,才能使代码按预期运行。

示例:Window.Activate()

以下是调用不受支持的 API Window.Activate() 的示例。 宏转换器会创建一个名称相似的新 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 具有多种返回类型,或者对象本身被声明为变体。

宏转换器会向此文件添加一个名为 __handle_resolve_<api>() 的新函数,该函数可替换有问题的 API 并帮助确定对象类型。

在某些情况下,您可能需要更新 __handle_resolve_<api>() 函数以手动声明对象类型。请参阅不支持的对象类型

示例:name()

VBA 中的许多对象类型都定义了 name() API。通常,Apps 脚本等效项为 getName(),但并非适用于所有对象类型。可能会出现多种替代情况:

  • 相应对象的 API 名称与 getName() 不同。
  • 该对象没有用于获取其名称的 Apps 脚本 API。
  • 没有等效的 Apps 脚本对象。

如果无法确定对象类型,宏转换器会在 variant_resolutions.gs 文件中创建一个名为 __handle_resolve_name 的新函数。

以下是代码示例:

原始 VBA 代码

a = Selection.name

在这种情况下,系统会对当前所选内容调用 API name()。所选内容可以是 Sheet 对象,也可以是 Shape 对象。如果它是工作表对象,则对应的翻译为 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 Script 运行时。

如果您使用的是默认的 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.gsvariant_resolution.gs 文件中遇到的大部分错误。

您可能会遇到的错误类型包括:

未实现的 API

未实现的 API 是指 Macro Converter 无法从 VBA 转换为 Apps 脚本的 API,并且没有针对该 API 的已知解决方法。

未实现的 API 通常会作为空函数(有时带有空签名)添加到 unimplemented_constructs.gs 文件中。如果无法确定对象类型,则未实现的 API 可能会添加到 variant_resolution.gs 文件中。

在转换之前生成的兼容性报告中,此 API 标记为需要进一步调查

如果您在转换文件之前未在 VBA 代码中修复此类 API,则该 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_<API_name>(param1, param2, ....) {
  ThrowException("API  not supported yet.");
}

修复了未实现的 API 错误

使用现有的 Apps 脚本 API 或 JS 库定义未实现的 API。 为此,请按以下步骤操作:

  1. 在错误位置打开转换后的 Apps 脚本代码。请参阅查找错误
  2. 在函数上方,阅读添加的注释。在某些情况下,注释会建议如何在 Apps 脚本中实现 API。
  3. 如果您找不到在 Apps 脚本中实现相应 API 的方法,请考虑从代码中移除该 API。
  4. 如果您找不到解决方法或无法从代码中移除此 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

在此示例中,您将了解:

  1. 如何将 name() API 转换为 variant_resolution.gs 文件中的新函数
  2. 转换后的代码中如何调用新函数
  3. 如何在 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")
Apps 脚本不支持 CommandBar,因此上述 VBA 代码中使用的两种方法也不受支持。
  • Application.CommandBars():在 VBA 中,此方法会返回所有 CommandBar 对象的列表。
  • CommandBars.item():在 VBA 中,此函数会返回特定的 CommandBar 对象。
由于 Apps 脚本不支持此对象类型,因此转换后的代码会在 `unimplemented_constructs.gs` 文件中创建以下函数,您需要定义这些函数。
  • _api_application_commandbars()
  • _api_commandbars_item()
转换后的代码中会调用这些函数,如下所示:
PrintName(_api_commandbars_item(_api_application_commandbars(), "Standard")))

Heres 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);
}

未实现的语言结构

构造是代码语言中用于控制执行流程或数据显示的元素。例如,循环、标签、事件和 goto。 以下是所有 VBA 结构的列表

宏转换器无法转换的构造会被视为未实现的语言构造

如果宏转换器确定存在未实现的语言结构,则会插入 TODO 注释。

不支持以下 VBA 构造:

修复未实现的语言结构错误

  1. 更新您的代码,使您的逻辑不再依赖于不受支持的语言结构。
  2. 在错误位置打开转换后的 Apps 脚本代码。请参阅查找错误
  3. 根据代码的逻辑,以不需要使用不受支持的语言结构的方式更新代码。
  4. 如果您找不到在不使用不受支持的语言结构的情况下重写代码的方法,则无法转换此宏。

未实现的语言结构错误示例

最常见的未实现语言结构之一是 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
等效的 Apps 脚本代码
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
等效的 Apps 脚本代码
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 函数,以将不受支持的值替换为符合您需求的合适解决方法。

  1. 在错误位置打开转换后的 Apps 脚本代码。请参阅查找错误
  2. 请阅读函数上方的注释,了解哪些值受支持,哪些值不受支持。
  3. 对于不支持的值,请确定哪些支持的值可以作为合适的替代值。
  4. 更新函数 _handle_<API_name>_error 以返回支持的值。
  5. 如果您找不到替换不受支持的值的方法,则无法转换此宏。

部分支持的 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,则该 API 在 Apps 脚本项目中的显示方式如下:

/**
* Could not convert  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.
*      : 
*
* 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_<API_name>(param1, param2, ....) {
 ThrowException("API  not supported yet.");
}

修正需要人工操作的错误

针对该 API 实现一种解决方法,使该 API 能够按预期运行。 1. 在错误位置打开转换后的 Apps 脚本代码。请参阅查找错误。 1. 请阅读函数上方的注释,了解哪些 API 可用于解决此问题。 1. 如果您找不到合适的解决方法,请考虑从代码中移除相应 API。 1. 如果您找不到解决方法或无法从代码中移除此 API,并且您的宏抛出错误,则无法转换此宏。

需要人工操作的错误示例

以下是一些会抛出“需要人工操作”错误的 API 示例以及如何修复这些错误:

示例 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() 替换为 Apps 脚本,无论在何处使用 Workbook.open() 打开文件 1:

var spreadSheetId =
   _handle_mso_excel_get_google_spreadsheet_id("C:\Data\abc.xlsx");
var spreadSheet = SpreadsheetApp.openById(spreadSheetId);
以下错误已添加到 Apps 脚本项目中的 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 脚本中,该代码会返回 undefined。

为避免出现意外结果,宏转换器会添加 Apps 脚本代码,以便在您尝试访问超出数组边界的元素时抛出异常。

以下代码中显示了此示例:

原始 VBA 代码
Dim arr
arr = Array("apple", "orange")
MsgBox arr(5)
Will throw the following error:
Subscript out of range
转换后的 Apps 脚本代码(添加异常错误之前)
var arr;
arr = ["apple", "orange"];
Browser.msgBox(arr[5]);
Will return this value and not throw an error:
undefined
添加了用于抛出异常错误的 Apps 脚本代码
/**
* 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));