修正轉換程式碼中的錯誤

巨集轉換程式外掛程式可自動執行大部分的轉換程序,但您可能需要調整某些 API 和其他項目,才能完成程式碼。

您可以參考本指南,瞭解新增至專案的 Apps Script 檔案 (GS 檔案)、解讀不同類型的錯誤,以及學習如何修正錯誤。

瞭解新增至專案的 Apps Script 檔案

我們會在 Apps Script 專案中新增其他 GS 檔案,協助您:

  • 定義 VBA 常數和 Apps Script 中不存在的值。
  • 實作未轉換的 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。您可能需要修改這個檔案,才能讓程式碼正常運作。

範例:Window.Activate()

以下為不支援的 API 示例:Window.Activate()。巨集轉換工具會建立名稱相似的新 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 有多個傳回類型,或是物件已宣告為變化版本。

巨集轉換器會在這個檔案中新增名為 __handle_resolve_<api>() 的新函式,用來取代相關 API,並協助判斷物件類型。

在某些情況下,您可能需要更新 __handle_resolve_<api>() 函式,才能手動宣告物件類型。請參閱不支援的物件類型

範例:name()

VBA 中的許多物件類型都會定義 name() API。通常,Apps Script 的等效值是 getName(),但並非適用於所有物件類型。可能會發生多種替代情況:

  • 物件的對等 API 呼叫與 getName() 不同的名稱。
  • 物件沒有 Apps Script API 可取得名稱。
  • 沒有等同的 Apps Script 物件。

如果未判斷物件類型,巨集轉換工具會在 variant_resolutions.gs 檔案中建立名為 __handle_resolve_name 的新函式。

以下是程式碼範例:

原始 VBA 程式碼

a = Selection.name

在這種情況下,系統會針對目前的選取項目呼叫 API name()。所選項目可以是工作表物件或形狀物件。如果是工作表物件,則轉譯為 getName(),但如果是形狀物件,則 Apps Script 中沒有等同的物件。

已轉換的 Apps Script 程式碼,已內嵌在程式碼中

a = __handle_resolve_name({}, getActiveSelection(), {});

系統會將下列 __handle_resolve_name() 函式新增至 variant_resolution.gs 檔案,以便解決不同物件類型的問題。函式會檢查物件類型,如果支援 getName(),就會使用 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)

這表示錯誤位於 unimplemented_constructs.gs 檔案中,第 2 行字元 (第 3 行)。

如果您使用的是已淘汰的 Rhino 執行階段,就會看到類似下方的錯誤訊息:

unimplemented_constructs:2 (_api_windows_active)

這表示錯誤位於第 2 行的 unimplemented_constructs.gs 檔案中。

錯誤類型

您可以修正上述 unimplemented_constructs.gsvariant_resolution.gs 檔案中遇到的大部分錯誤。

您可能會遇到的錯誤類型包括:

未實作的 API

未實作的 API 是指 Macro Converter 無法將其從 VBA 轉換為 Apps Script,且沒有已知的 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_<API_name>(param1, param2, ....) {
  ThrowException("API  not supported yet.");
}

修正未實作的 API 錯誤

使用現有的 Apps Script API 或 JS 程式庫定義未實作的 API。步驟如下:

  1. 在錯誤位置開啟已轉換的 Apps Script 程式碼。請參閱「找出錯誤」一文。
  2. 請閱讀函式上方新增的註解。在某些情況下,註解會建議如何在 Apps Script 中實作 API。
  3. 如果無法在 Apps Script 中導入 API,建議您從程式碼中移除該 API。
  4. 如果您找不到解決方法,或是無法從程式碼中移除這個 API,且巨集擲回這個錯誤,就無法轉換這個巨集。

未實作 API 錯誤的範例

以下列舉未實作的 API 情境,以及如何修正這些情境:

  • 沒有等同的 Apps Script:針對 Chart.Protect (Apps Script 中不存在的 API) 顯示間接解決方法。
  • 不明物件類型:說明如何處理變數的物件類型,以及如何實作不支援的物件類型 (可在 Apps Script 中重新建立)。
範例 1:沒有等同的 Apps Script 或不明 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. 如何在 variant_resolution.gs 檔案中將 name() API 轉換為新函式
  2. 在轉換後的程式碼中如何呼叫新函式
  3. 如何在 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 Script 程式碼會呼叫 `__handle_resolve_name` 函式:
function PrintName(obj) {
  Logger.log(_handle_resolve_name(obj));
}

3. 假設 VBA 程式碼對物件類型 CommandBar 呼叫 PrintName() 函式。以下是 VBA 程式碼:

PrintName Application.CommandBars.item("Standard")
Apps Script 不支援 CommandBar,因此也不支援上述 VBA 程式碼中使用的兩個方法。
  • Application.CommandBars():在 VBA 中,這會傳回所有 CommandBar 物件的清單。
  • CommandBars.item():在 VBA 中,這個方法會傳回特定 CommandBar 物件。
由於 Apps Script 不支援此物件類型,轉換後的程式碼會在您必須定義的「unimplementationed_建構.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 Script 程式碼。請參閱「找出錯誤」一文。
  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 Script 程式碼
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 Script 程式碼
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 函式,以便將不支援的值替換為符合需求的可接受替代方案。

  1. 在錯誤位置開啟已轉換的 Apps Script 程式碼。請參閱「找出錯誤」一文。
  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 Script,但需要替代方案。

在轉換前產生的相容性報告中,這類 API 會標示為「支援,但有因應措施」

如果您在轉換檔案前未在 VBA 程式碼中修正這類 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 Script 程式碼。請參閱「找出錯誤」一文。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() 開啟檔案 1 的地方,將 Workbook.open() 替換為 Apps Script:

var spreadSheetId =
   _handle_mso_excel_get_google_spreadsheet_id("C:\Data\abc.xlsx");
var spreadSheet = SpreadsheetApp.openById(spreadSheetId);
以下錯誤會新增至 Apps Script 專案中的 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 中,程式碼會傳回 undefined。

為了避免非預期的結果,巨集轉換工具會新增 Apps Script 程式碼,如果您嘗試存取超出陣列邊界的元素,就會擲回例外狀況。

以下程式碼顯示這個範例:

原始 VBA 程式碼
Dim arr
arr = Array("apple", "orange")
MsgBox arr(5)
Will throw the following error:
Subscript out of range
已轉換的 Apps Script 程式碼 (在新增例外狀況錯誤之前)
var arr;
arr = ["apple", "orange"];
Browser.msgBox(arr[5]);
Will return this value and not throw an error:
undefined
新增 Apps Script 程式碼,以便擲回例外狀況錯誤
/**
* 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));