Sửa lỗi trong mã đã chuyển đổi của bạn

Tiện ích bổ sung Trình chuyển đổi macro sẽ tự động hoá hầu hết quá trình chuyển đổi, nhưng bạn có thể cần phải điều chỉnh một số API và các mục khác để hoàn tất mã của mình.

Hãy làm theo hướng dẫn này để tìm hiểu các tệp Apps Script (tệp GS) được thêm vào dự án của bạn, diễn giải các loại lỗi và tìm hiểu cách sửa lỗi.

Tìm hiểu về các tệp Apps Script được thêm vào dự án của bạn

Các tệp GS bổ sung được thêm vào dự án Apps Script để giúp:

  • Xác định các hằng số và giá trị VBA không tồn tại trong Apps Script.
  • Triển khai các API chưa chuyển đổi.
  • Giải quyết biến thể.

Các tệp GS sau được thêm vào dự án Apps Script của bạn:

  • Library.gs
  • Unimplemented_constructs.gs
  • Variant_resolutions.gs

Library.gs

Nhìn chung, bạn không cần sửa đổi gì trong tệp library.gs.

Tệp library.gs xác định các hàm và hằng số được dùng trong mã VBA nhưng không tồn tại trong Apps Script. Điều này giúp mã Apps Script mới giống với mã VBA của bạn hơn. Ngoài ra, bạn không cần lặp lại các định nghĩa mỗi khi sử dụng các hàm hoặc hằng số trong tệp library.gs.

Unimplemented_constructs.gs

Tệp unimplemented_constructs.gs đề cập đến các cấu trúc hoặc API không chuyển đổi được bằng Trình chuyển đổi macro. Có thể bạn sẽ phải sửa đổi tệp này để mã của mình hoạt động như dự kiến.

Ví dụ: Window.Activate()

Sau đây là ví dụ về một API không được hỗ trợ có tên là Window.Activate(). Trình chuyển đổi macro sẽ tạo một hàm Apps Script mới có tên tương tự và xác định hàm đó trong tệp unimplemented_constructs.gs. Vì chức năng VBA không được hỗ trợ nên hàm Apps Script mới sẽ tạo ra một ngoại lệ.

Hàm mới được thêm vào mã Apps Script đã chuyển đổi ở mọi nơi API gốc được sử dụng trong mã VBA.

Nếu tìm được giải pháp để tạo lại hành vi của API gốc, thì bạn chỉ cần cập nhật định nghĩa của hàm này trong tệp unimplemented_constructs.gs. Sau khi hàm được xác định ở đó, hàm này sẽ áp dụng ở mọi nơi mà hàm đó xuất hiện trong dự án Apps Script của bạn.

Sau đây là ví dụ trong mã:

Mã VBA gốc

Window.activate()

Mã Apps Script đã chuyển đổi, được thêm vào cùng dòng

_api_window_activate();

Đã thêm định nghĩa hàm vào tệp 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

Tệp variant_resolutions.gs sẽ được thêm vào dự án Apps Script nếu không thể xác định loại đối tượng. Điều này có thể xảy ra vì nhiều lý do, chẳng hạn như API có nhiều loại dữ liệu trả về hoặc đối tượng được khai báo là một biến thể.

Trình chuyển đổi macro sẽ thêm một hàm mới có tên là __handle_resolve_<api>() vào tệp này để thay thế API được đề cập và giúp xác định loại đối tượng.

Trong một số trường hợp, bạn có thể cần phải cập nhật hàm __handle_resolve_<api>() để khai báo loại đối tượng theo cách thủ công. Xem phần Loại đối tượng không được hỗ trợ.

Ví dụ: name()

Nhiều loại đối tượng trong VBA xác định một API name(). Thông thường, Apps Script tương đương với getName(), nhưng không phải cho mọi loại đối tượng. Có thể xảy ra nhiều trường hợp thay thế:

  • API tương đương của đối tượng được gọi là API khác với getName().
  • Đối tượng không có API Apps Script để lấy tên.
  • Không có đối tượng Apps Script tương đương.

Khi loại đối tượng không được xác định, Trình chuyển đổi macro sẽ tạo một hàm mới có tên là __handle_resolve_name trong tệp variant_resolutions.gs.

Sau đây là ví dụ trong mã:

Mã VBA gốc

a = Selection.name

Trong trường hợp này, API name() được gọi trên lựa chọn hiện tại. Lựa chọn này có thể là đối tượng Trang tính hoặc đối tượng Hình dạng. Nếu đó là đối tượng Trang tính, bản dịch sẽ là getName(), nhưng nếu đó là đối tượng Hình dạng thì không có đối tượng nào tương đương trong Apps Script.

Mã Apps Script đã chuyển đổi, được thêm vào cùng dòng

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

Hàm __handle_resolve_name() dưới đây được thêm vào tệp variant_resolution.gs để giải quyết các loại đối tượng khác nhau. Hàm này sẽ kiểm tra loại đối tượng, sau đó sử dụng getName() nếu được hỗ trợ hoặc gửi lỗi nếu getName() không được hỗ trợ.

Đã thêm định nghĩa hàm vào tệp 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;
}

Tìm lỗi

Khi bạn gặp lỗi trong mã Apps Script đã chuyển đổi, thông báo sẽ chỉ định loại lỗi và vị trí tương ứng. Định dạng của thông báo lỗi phụ thuộc vào thời gian chạy Apps Script mà bạn đang sử dụng.

Nếu đang sử dụng thời gian chạy V8 mặc định, bạn sẽ thấy một lỗi có dạng như sau:

_api_windows_active (unimplemented_constructs:2:3)

Điều này có nghĩa là lỗi nằm trong tệp unimplemented_constructs.gs ở dòng 2, ký tự 3.

Nếu đang sử dụng thời gian chạy Rhino không dùng nữa, bạn sẽ thấy một lỗi có dạng như sau:

unimplemented_constructs:2 (_api_windows_active)

Điều này có nghĩa là lỗi nằm trong tệp unimplemented_constructs.gs ở dòng 2.

Các loại lỗi

Bạn có thể khắc phục hầu hết lỗi mình gặp phải trong các tệp unimplemented_constructs.gsvariant_resolution.gs được mô tả ở trên.

Các loại lỗi bạn có thể gặp phải bao gồm:

API chưa triển khai

API chưa triển khai là một API mà Trình chuyển đổi macro không thể chuyển đổi từ VBA sang Apps Script và chưa có giải pháp đã biết nào cho API này.

Các API chưa triển khai thường được thêm dưới dạng các hàm trống (đôi khi có chữ ký trống) vào tệp unimplemented_constructs.gs. Nếu không thể xác định loại đối tượng, thì API chưa triển khai có thể được thêm vào tệp variant_resolution.gs.

Trong báo cáo về khả năng tương thích mà bạn đã tạo trước khi chuyển đổi, API này được gắn nhãn là Cần điều tra thêm.

Nếu bạn không khắc phục loại API này trong mã VBA trước khi chuyển đổi tệp, thì dưới đây là cách API xuất hiện trong dự án 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.");
}

Sửa lỗi API chưa triển khai

Xác định API chưa triển khai với các API Apps Script hoặc thư viện JS hiện có. Để thực hiện việc này, hãy làm theo các bước sau:

  1. Mở mã Apps Script đã chuyển đổi ở vị trí xảy ra lỗi. Xem phần Tìm lỗi.
  2. Phía trên hàm này, hãy đọc nhận xét đã được thêm. Trong một số trường hợp, nhận xét đó sẽ đề xuất cách triển khai API trong Apps Script.
  3. Nếu bạn không tìm thấy cách triển khai API trong Apps Script, hãy cân nhắc xoá API đó khỏi mã của bạn.
  4. Nếu không tìm thấy giải pháp hoặc xoá API này khỏi mã và macro trả về lỗi này, thì bạn không thể chuyển đổi macro này.

Ví dụ về lỗi API chưa triển khai

Dưới đây là ví dụ về các trường hợp API chưa triển khai và cách khắc phục:

Ví dụ 1: Không có Apps Script tương đương hoặc API không xác định

Trong ví dụ này, Chart.Protect không được tự động chuyển đổi vì không có cách nào để bảo vệ biểu đồ trong Google Trang tính.

/**
* 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.');
}
Mặc dù không thể bảo vệ biểu đồ, nhưng bạn có thể bảo vệ phạm vi dữ liệu của biểu đồ để dữ liệu không bị thay đổi.

Dưới đây là một ví dụ về cách triển khai việc bảo vệ dải ô:
/**
* 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();
}
}
Ví dụ 2: Loại đối tượng không được hỗ trợ

Khi không xác định được loại đối tượng, lỗi API chưa triển khai sẽ được thêm vào tệp variant_resolution.gs. Ví dụ sau mở rộng dựa trên ví dụ về API VBA name() ở trên. Hãy xem variant_resolution.gs.

Trong ví dụ này, bạn sẽ tìm hiểu:

  1. Cách chuyển đổi API name() thành hàm mới trong tệp variant_resolution.gs.
  2. Cách gọi hàm mới trong mã đã chuyển đổi.
  3. Cách tạo giải pháp cho CommandBar (một loại đối tượng không được hỗ trợ) trong Apps Script.

1. Vì mã đã chuyển đổi không thể xác định chính xác loại đối tượng name() được gọi, nên Trình chuyển đổi macro sẽ tạo một hàm mới có tên là __handle_resolve_name như bên dưới.

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. Giả sử mã VBA xác định một hàm PrintName() gọi API name(). Mã VBA được hiển thị bên dưới:

‘Defining a function that prints the name of the object in parameter
Sub PrintName(obj as Variant)
  Debug.Print obj.Name
End Sub
Vì "name()" được gọi trên một đối tượng là biến, nên mã đã chuyển đổi không biết loại đối tượng tại thời điểm chuyển đổi. Mã Apps Script đã chuyển đổi sẽ gọi hàm "__handle_resolve_name":
function PrintName(obj) {
  Logger.log(_handle_resolve_name(obj));
}

3. Giả sử mã VBA của bạn gọi hàm PrintName() trên kiểu đối tượng CommandBar. Mã VBA được hiển thị bên dưới:

PrintName Application.CommandBars.item("Standard")
CommandBar không được hỗ trợ trong Apps Script nên 2 phương thức dùng trong mã VBA ở trên cũng không được hỗ trợ.
  • Application.CommandBars(): Trong VBA, thao tác này sẽ trả về danh sách tất cả đối tượng CommandBar.
  • CommandBars.item(): Trong VBA, phương thức này sẽ trả về một đối tượng CommandBar cụ thể.
Vì loại đối tượng này không được hỗ trợ trong Apps Script, nên mã đã chuyển đổi sẽ tạo các hàm sau đây trong tệp "unimplementationed_constructs.gs" mà bạn cần xác định.
  • _api_application_commandbars()
  • _api_commandbars_item()
Các hàm được gọi trong mã chuyển đổi như minh hoạ dưới đây:
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.');
}

Để các hàm mới hoạt động, hãy làm theo các bước sau:

3.1 Xác định loại đối tượng mới tạo các chức năng của CommandBars và một tập hợp mới của CommandBars tương tự như nội dung tồn tại trong VBA.

3.2 Thêm phương thức getName() cho loại đối tượng mới.

Bước 3.1 và 3.2 được thể hiện trong đoạn mã dưới đây. Các đối tượng trình đơn được tạo dưới dạng kiểu đối tượng mới bắt chước hành vi của 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 Sửa đổi hàm __handle_resolve_name trong tệp variant_resolution.gs để xử lý loại đối tượng mới. Thêm một phần vào hàm như minh hoạ dưới đây:

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 Xác định 2 hàm được tạo trong tệp unimplemented_constructs.gs (_api_application_commandbars(), _api_commandbars_item()). Bước này đảm bảo các lệnh gọi ban đầu của hàm sẽ hoạt động.

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

Cấu trúc ngôn ngữ chưa được triển khai

construct là một phần tử của ngôn ngữ mã kiểm soát luồng thực thi hoặc chế độ hiển thị dữ liệu. Ví dụ: vòng lặp, nhãn, sự kiện và gotos. Dưới đây là danh sách tất cả các cấu trúc VBA.

Các cấu trúc mà Trình chuyển đổi macro không thể chuyển đổi được coi là cấu trúc ngôn ngữ chưa triển khai.

Khi xác định rằng có một cấu trúc ngôn ngữ chưa được triển khai, Trình chuyển đổi macro sẽ chèn một nhận xét TODO.

Các cấu trúc VBA sau không được hỗ trợ:

Sửa lỗi cấu trúc ngôn ngữ chưa triển khai

  1. Hãy cập nhật mã để logic của bạn không dựa vào cấu trúc ngôn ngữ không được hỗ trợ.
  2. Mở mã Apps Script đã chuyển đổi ở vị trí xảy ra lỗi. Hãy xem mục Tìm lỗi.
  3. Dựa trên logic của mã, hãy cập nhật mã theo cách không yêu cầu cấu trúc ngôn ngữ không được hỗ trợ.
  4. Nếu không thể tìm cách viết lại mã mà không có cấu trúc ngôn ngữ không được hỗ trợ, thì bạn không thể chuyển đổi macro này.

Ví dụ về lỗi cấu trúc ngôn ngữ chưa triển khai

Một trong những cấu trúc ngôn ngữ chưa được triển khai phổ biến nhất là câu lệnh GoTo. Bạn có thể thay thế một số câu lệnh GoTo của VBA bằng vòng lặp. Dưới đây là hai ví dụ về cách sử dụng vòng lặp thay vì câu lệnh GoTo.

Ví dụ 1: Thay thế GoTo bằng While Loop

Mã VBA gốc
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
Mã Apps Script tương đương
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);
}

Ví dụ 2: Thay thế GoTo bằng For Loop

Mã VBA gốc
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
Mã Apps Script tương đương
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 được hỗ trợ một phần

Đối với API được hỗ trợ một phần, một số tham số đầu vào được hỗ trợ trong Apps Script và một số tham số thì không.

Ví dụ: API VBA legend_position được dùng để xác định chú giải trong biểu đồ Excel. Mô-đun này hỗ trợ nhiều loại giá trị đầu vào, bao gồm:

  • xlLegendPositionBottom: Đặt chú giải ở cuối biểu đồ.
  • xlLegendPositionCorner: Đặt chú giải ở góc biểu đồ.
  • xlLegendPositionCustom: Đặt chú giải tại các vị trí tuỳ chỉnh trên biểu đồ.

Apps Script có một mã tương đương chỉ hỗ trợ một số giá trị trong số đó. Các giá trị sau không được hỗ trợ:

  • xlLegendPositionCorner
  • xlLegendPositionCustom

Để gắn cờ những giá trị không được hỗ trợ của API được hỗ trợ một phần trong mã chuyển đổi, điều kiện xác thực sẽ được thêm vào tệp library.gs nhằm kiểm tra các giá trị đó. Ví dụ:

if (position == xlLegendPositionCorner ||
     position == xlLegendPositionCustom) {
   position = _handle_legend_position_error(position);
}

Nếu điều kiện xác thực tìm thấy một trong những giá trị không được hỗ trợ, thì hàm xử lý lỗi _handle_<API_name>_error sẽ được tạo trong tệp unimplemented_constructs.gs.

Hàm này báo lỗi người dùng và sẽ không thay thế giá trị đó bằng một giá trị được hỗ trợ. Ví dụ:

/**
* 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);
}

Khắc phục một phần lỗi API được hỗ trợ

Xác định hàm _handle_<API_name>_error để thay thế các giá trị không được hỗ trợ bằng giải pháp phù hợp với nhu cầu của bạn.

  1. Mở mã Apps Script đã chuyển đổi ở vị trí xảy ra lỗi. Xem phần Tìm lỗi.
  2. Đọc nhận xét phía trên hàm này để biết giá trị nào được hỗ trợ và giá trị nào không được hỗ trợ.
  3. Đối với các giá trị không được hỗ trợ, hãy xác định những giá trị được hỗ trợ có thể đóng vai trò là giá trị thay thế phù hợp.
  4. Cập nhật hàm _handle_<API_name>_error để trả về một giá trị được hỗ trợ.
  5. Nếu không thể tìm cách thay thế giá trị không được hỗ trợ, bạn không thể chuyển đổi macro này.

Ví dụ về lỗi API được hỗ trợ một phần

Ví dụ sau mở rộng trên API VBA legend_position nêu trên. Hãy xem nội dung API được hỗ trợ một phần.

Dưới đây là ví dụ về mã VBA gốc sử dụng giá trị không được hỗ trợ, xlLegendPositionCustom.

Charts(1).Legend.Position = xlLegendPositionCustom

Trình chuyển đổi macro sẽ thêm hàm bên dưới vào tệp 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);
}

Cần thực hiện thao tác thủ công

Cần thực hiện thao tác thủ công có nghĩa là bạn có thể chuyển đổi VBA API thành Apps Script, nhưng cần có một giải pháp.

Trong báo cáo về khả năng tương thích mà bạn đã tạo trước khi chuyển đổi, loại API này sẽ được gắn nhãn là Có giải pháp được hỗ trợ.

Nếu bạn không khắc phục loại API này trong mã VBA trước khi chuyển đổi tệp, thì dưới đây là cách API xuất hiện trong dự án Apps Script:

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

Khắc phục lỗi cần thực hiện công việc thủ công

Triển khai một giải pháp để API hoạt động như dự kiến. 1. Mở mã Apps Script đã chuyển đổi ở vị trí xảy ra lỗi. Hãy xem phần Tìm lỗi. 1. Đọc nhận xét phía trên hàm này để hiểu được có thể dùng API nào để giải quyết vấn đề. 1. Nếu bạn không tìm thấy giải pháp phù hợp, hãy cân nhắc việc xoá API này khỏi mã của bạn. 1. Nếu không tìm thấy giải pháp hoặc xoá API này khỏi mã của mình và macro trả về lỗi, thì bạn không thể chuyển đổi macro này.

Ví dụ về lỗi cần thực hiện thủ công

Dưới đây là ví dụ về những API gặp phải lỗi cần thực hiện Quy trình thủ công và cách khắc phục:

Ví dụ 1: Autocorrect.Addreplacement

Trong ví dụ sau, Autocorrect.Addreplacement API VBA có thể được chuyển đổi, nhưng cần có một giải pháp. Trình chuyển đổi macro đề xuất cách triển khai hàm trong phần nhận xét mã.

/**
* 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.');

}

Dưới đây là cách triển khai 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));
}

Ví dụ 2: Workbook.open()

API VBA workbook.open() mở một tệp cục bộ dựa trên đường dẫn tệp.

Giả sử có hai tệp đang được workbook.open() mở trong mã VBA:

  • Tệp 1: C:\Data\abc.xlsx
  • Tệp 2: C:\Data\xyz.xlsx

Bên dưới là cách Trình chuyển đổi macro thay thế Workbook.open() bằng Apps Script ở mọi nơi sử dụng Workbook.open() để mở Tệp 1:

var spreadSheetId =
   _handle_mso_excel_get_google_spreadsheet_id("C:\Data\abc.xlsx");
var spreadSheet = SpreadsheetApp.openById(spreadSheetId);
Lỗi dưới đây được thêm vào tệp unimplemented_constructs.gs trong dự án Apps Script:
/**
* 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 '';
}

Theo hướng dẫn trong các nhận xét trong mẫu ở trên, bạn cần chuyển đổi các tệp mục tiêu thành tệp Google Trang tính trên Google Drive.

Các mã bảng tính Google tương ứng được in đậm bên dưới:

  • Tệp #1: C:\Data\abc.xlsx trở thành https://docs.google.com/spreadsheets/d/abc123Abc123Abc123abc
  • Tệp #2: C:\Data\abc.xlsx trở thành https://docs.google.com/spreadsheets/d/xyz456Xyz456xYz456xyZ

Sau đó, hãy sửa đổi mã trong hàm Apps Script để mở tệp theo mã nhận dạng, như minh hoạ dưới đây:

/**
* 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";
 }

Lỗi có chủ ý

Lỗi có chủ ý được thêm vào mã đã chuyển đổi để bắt chước hành vi lỗi của mã VBA gốc. Bạn không cần sửa đổi những lỗi này.

Ví dụ về lỗi cố ý

Nếu bạn cố gắng truy cập vào một phần tử nằm ngoài giới hạn của một mảng trong VBA, thì mã sẽ gửi ra một ngoại lệ. Trong Apps Script, mã trả về không xác định.

Để tránh kết quả không mong muốn, Trình chuyển đổi macro sẽ thêm mã Apps Script cho ra trường hợp ngoại lệ nếu bạn cố gắng truy cập vào các phần tử nằm ngoài giới hạn của một mảng.

Ví dụ này được minh hoạ trong mã dưới đây:

Mã VBA gốc
Dim arr
arr = Array("apple", "orange")
MsgBox arr(5)
Will throw the following error:
Subscript out of range
Mã Apps Script đã chuyển đổi (trước khi thêm lỗi ngoại lệ)
var arr;
arr = ["apple", "orange"];
Browser.msgBox(arr[5]);
Will return this value and not throw an error:
undefined
Thêm mã Apps Script để gửi lỗi ngoại lệ
/**
* 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));