แก้ไขข้อผิดพลาดในโค้ดที่แปลงแล้ว

ส่วนเสริม Macro Converter จะทำให้กระบวนการแปลงส่วนใหญ่เป็นแบบอัตโนมัติ แต่คุณอาจต้องปรับ API บางรายการและรายการอื่นๆ เพื่อสรุปโค้ด

ใช้คู่มือนี้เพื่อทำความเข้าใจไฟล์ Apps Script (ไฟล์ GS) ที่เพิ่มลงในโปรเจ็กต์ ตีความข้อผิดพลาดประเภทต่างๆ และดูวิธีแก้ไขข้อผิดพลาด

ทำความเข้าใจไฟล์ Apps Script ที่เพิ่มลงในโปรเจ็กต์

ระบบจะเพิ่มไฟล์ GS อื่นๆ ลงในโปรเจ็กต์ Apps Script เพื่อช่วยในเรื่องต่อไปนี้

  • กำหนดค่าคงที่และค่า 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 ที่แปลงแล้วทุกที่ที่มีการใช้ API เดิมในโค้ด VBA

หากพบวิธีแก้ปัญหาเพื่อสร้างลักษณะการทำงานของ 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 กำหนด API name() โดยปกติแล้วฟังก์ชันที่เทียบเท่าใน Apps Script คือ getName() แต่ไม่ใช่สำหรับออบเจ็กต์ทุกประเภท กรณีที่อาจเกิดขึ้นได้มีดังนี้

  • API ที่เทียบเท่าของออบเจ็กต์มีชื่อแตกต่างจาก getName()
  • ออบเจ็กต์ไม่มี Apps Script API เพื่อรับชื่อ
  • ไม่มีออบเจ็กต์ Apps Script ที่เทียบเท่า

เมื่อไม่สามารถระบุประเภทออบเจ็กต์ได้ ตัวแปลงมาโครจะสร้างฟังก์ชันใหม่ชื่อ __handle_resolve_name ในไฟล์ variant_resolutions.gs

ตัวอย่างในโค้ดมีดังนี้

โค้ด VBA เดิม

a = Selection.name

ในกรณีนี้ ระบบจะเรียกใช้ API name() กับรายการที่เลือกในปัจจุบัน การเลือก อาจเป็นออบเจ็กต์ชีตหรือออบเจ็กต์รูปร่าง หากเป็นออบเจ็กต์ชีต การแปลคือ getName() แต่หากเป็นออบเจ็กต์รูปร่าง จะไม่มีค่าเทียบเท่าใน Apps Script

โค้ด Apps Script ที่แปลงแล้วและเพิ่มไว้ในบรรทัด

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

ฟังก์ชัน __handle_resolve_name() ด้านล่างจะเพิ่มลงในไฟล์ variant_resolution.gs เพื่อแก้ปัญหาสำหรับออบเจ็กต์ประเภทต่างๆ ฟังก์ชัน จะตรวจสอบประเภทออบเจ็กต์ จากนั้นจะใช้ getName() หากรองรับ หรือแสดงข้อผิดพลาดหากไม่รองรับ getName()

เพิ่มคำจำกัดความฟังก์ชันลงในไฟล์ variant_resolution.gs

function __handle_resolve_name(ExecutionContext, CallingObject, params_map) {
  var found_api_variant = false;
  var return_value;
  if (String(CallingObject) == "Sheet") {
    if (!ExecutionContext.isLhs) {
      return_value = CallingObject.getName();
      found_api_variant = true;
    }
  }
  if (CallingObject instanceof ChartInSheet) {
    if (!ExecutionContext.isLhs) {
      return_value = CallingObject.getName();
      found_api_variant = true;
    }
  }
  if (!found_api_variant) {
    ThrowException("API .name not supported yet.");
  }
  return return_value;
}

ค้นหาข้อผิดพลาด

เมื่อพบข้อผิดพลาดในโค้ด Apps Script ที่แปลงแล้ว ข้อความจะระบุประเภทของข้อผิดพลาดและตำแหน่งของข้อผิดพลาด รูปแบบของข้อความแสดงข้อผิดพลาด จะขึ้นอยู่กับรันไทม์ Apps Script ที่คุณใช้

หากใช้รันไทม์ V8 เริ่มต้น คุณจะเห็นข้อผิดพลาดที่มีลักษณะดังต่อไปนี้

_api_windows_active (unimplemented_constructs:2:3)

ซึ่งหมายความว่าข้อผิดพลาดอยู่ในไฟล์ unimplemented_constructs.gs ที่บรรทัด 2 อักขระที่ 3

หากคุณใช้รันไทม์ Rhino ที่เลิกใช้งานแล้ว คุณจะเห็นข้อผิดพลาดที่คล้ายกับข้อความต่อไปนี้

unimplemented_constructs:2 (_api_windows_active)

ซึ่งหมายความว่าข้อผิดพลาดอยู่ในไฟล์ unimplemented_constructs.gs ที่ บรรทัดที่ 2

ประเภทข้อผิดพลาด

คุณแก้ไขข้อผิดพลาดส่วนใหญ่ที่พบในไฟล์ unimplemented_constructs.gs และ variant_resolution.gs ที่อธิบายไว้ข้างต้นได้

ประเภทข้อผิดพลาดที่คุณอาจพบมีดังนี้

API ที่ยังไม่ได้ใช้งาน

API ที่ไม่ได้ใช้คือ API ที่ตัวแปลงมาโครไม่สามารถแปลงจาก VBA เป็น Apps Script และไม่มีวิธีแก้ปัญหาที่ทราบสำหรับ API

โดยปกติแล้ว เราจะเพิ่ม API ที่ยังไม่ได้ใช้งานเป็นฟังก์ชันว่าง (บางครั้งก็มีลายเซ็นว่าง) ลงในไฟล์ unimplemented_constructs.gs หากระบุประเภทออบเจ็กต์ไม่ได้ ระบบอาจเพิ่ม API ที่ยังไม่ได้ใช้งานลงในไฟล์ variant_resolution.gs แทน

ในรายงานความเข้ากันได้ที่คุณสร้างขึ้นก่อนการแปลง API นี้จะ ระบุว่าต้องตรวจสอบเพิ่มเติม

หากคุณไม่แก้ไข API ประเภทนี้ในโค้ด VBA ก่อนที่จะแปลงไฟล์ ลักษณะที่ปรากฏในโปรเจ็กต์ 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 ที่ไม่ได้ติดตั้งใช้งาน

กำหนด API ที่ยังไม่ได้ใช้งานด้วย Apps Script API หรือไลบรารี JS ที่มีอยู่ โดยทำตามขั้นตอนต่อไปนี้

  1. เปิดโค้ด Apps Script ที่แปลงแล้วในตำแหน่งที่เกิดข้อผิดพลาด ดูค้นหาข้อผิดพลาด
  2. อ่านความคิดเห็นที่เพิ่มไว้เหนือฟังก์ชัน ในบางกรณี ความคิดเห็นจะแนะนำวิธีใช้ API ใน Apps Script
  3. หากไม่พบวิธีติดตั้งใช้งาน API ใน Apps Script ให้ลอง นำออกจากโค้ด
  4. หากคุณไม่พบวิธีแก้ปัญหาชั่วคราวหรือนำ API นี้ออกจากโค้ด และมาโครแสดงข้อผิดพลาดนี้ คุณจะแปลงมาโครนี้ไม่ได้

ตัวอย่างข้อผิดพลาดของ API ที่ไม่ได้ใช้

ต่อไปนี้คือตัวอย่างสถานการณ์ API ที่ไม่ได้ใช้และวิธีแก้ไข

ตัวอย่างที่ 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 ตัวอย่างต่อไปนี้จะขยายความจากname() ตัวอย่าง API ของ VBA ด้านบน ดู variant_resolution.gs

ในตัวอย่างนี้ คุณจะได้เรียนรู้สิ่งต่อไปนี้

  1. วิธีแปลง name() API เป็นฟังก์ชันใหม่ในไฟล์ variant_resolution.gs
  2. วิธีเรียกใช้ฟังก์ชันใหม่ในโค้ดที่แปลงแล้ว
  3. วิธีสร้างวิธีแก้ปัญหาชั่วคราวสำหรับ CommandBar ซึ่งเป็นประเภทออบเจ็กต์ที่ไม่รองรับ ใน Apps Script

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 กำหนดฟังก์ชัน PrintName() ที่เรียกใช้ name() API โค้ด 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 เรียกใช้ฟังก์ชัน PrintName() ในประเภทออบเจ็กต์ CommandBar โค้ด VBA จะแสดงอยู่ด้านล่าง

PrintName Application.CommandBars.item("Standard")
CommandBar ไม่รองรับใน Apps Script และด้วยเหตุนี้ วิธีการ 2 วิธีที่ใช้ในโค้ด VBA ข้างต้นจึงไม่รองรับด้วย
  • Application.CommandBars(): ใน VBA คำสั่งนี้จะแสดงรายการออบเจ็กต์ CommandBar ทั้งหมด
  • CommandBars.item(): ใน VBA คำสั่งนี้จะแสดงผลออบเจ็กต์ CommandBarที่เฉพาะเจาะจง
เนื่องจาก Apps Script ไม่รองรับออบเจ็กต์ประเภทนี้ โค้ดที่แปลงแล้ว จึงสร้างฟังก์ชันต่อไปนี้ในไฟล์ `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 และคอลเล็กชันใหม่ของ CommandBars คล้ายกับที่มีอยู่ใน VBA

3.2 เพิ่มgetName()เมธอดสำหรับประเภทออบเจ็กต์ใหม่

ขั้นตอนที่ 3.1 และ 3.2 แสดงอยู่ในโค้ดด้านล่าง ระบบจะสร้างออบเจ็กต์เมนูเป็น ออบเจ็กต์ประเภทใหม่ที่เลียนแบบลักษณะการทำงานของ CommandBars

// Our Implementation of CommandBar using Menu objects.

function CommandBar(name) {
  this.name = name;
  // Create a menu object to represent the commandbar.
  this.menu = SpreadsheetApp.getUi().createMenu(name);
  // Create methods for retrieving or updating the name of the object
  this.getName = function() {
    return this.name;
  };
  this.updateName = function(name) {
    this.name = name;
  };
  // ========================================================================
  // Implement other methods of CommandBar objects that are used in the script.
  // =====================================================================
  return this;
}
// Our implementation of the collection of CommandBars that exists in VBA
function CommandBars() {
  this.commandBars = [];
  this.getCommandBar = function(name) {
    for (var i = 0; i < this.commandBars.length; i++) {
      if (!this.commandBars[i].getName() == name) {
        return this.commandBars[i];
      }
    }
    // No commandBar with the name exists, create a new one and return.
    var commandBar = new CommandBar(name);
    this.commandBars.push(commandBar);
    return commandBar;
  };
  return this;
}
// Create a global object that represents CommandBars collection.
var GlobalCommandBars = new CommandBars();

3.3 แก้ไขฟังก์ชัน __handle_resolve_name ในไฟล์ 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;
   }
 }
 // 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 กำหนดฟังก์ชัน 2 รายการที่สร้างในไฟล์ 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 ทั้งหมดมีดังนี้

โครงสร้างที่ Macro Converter แปลงไม่ได้ถือเป็นโครงสร้างภาษาที่ยังไม่ได้ใช้

เมื่อตัวแปลงมาโครพิจารณาว่ามีโครงสร้างภาษาที่ไม่ได้ใช้ อยู่ ก็จะแทรกTODOความคิดเห็น

ระบบไม่รองรับโครงสร้าง VBA ต่อไปนี้

แก้ไขข้อผิดพลาดเกี่ยวกับโครงสร้างภาษาที่ไม่ได้ใช้

  1. อัปเดตโค้ดเพื่อให้ตรรกะไม่ต้องอาศัยโครงสร้างภาษาที่ไม่รองรับ
  2. เปิดโค้ด Apps Script ที่แปลงแล้วในตำแหน่งที่เกิดข้อผิดพลาด ดูค้นหา ข้อผิดพลาด
  3. อัปเดตโค้ดตามตรรกะของโค้ดในลักษณะที่ไม่ต้องใช้โครงสร้างภาษาที่ไม่รองรับ
  4. หากไม่พบวิธีเขียนโค้ดใหม่โดยไม่มีโครงสร้างภาษาที่ไม่รองรับ คุณจะแปลงมาโครนี้ไม่ได้

ตัวอย่างข้อผิดพลาดของโครงสร้างภาษาที่ไม่ได้ใช้

หนึ่งในโครงสร้างภาษาที่พบบ่อยที่สุดซึ่งไม่ได้ใช้คือคำสั่ง GoTo คุณสามารถแทนที่คำสั่ง VBA GoTo บางคำสั่งด้วยลูปได้ ตัวอย่าง 2 รายการด้านล่างแสดงการ ใช้ลูปแทนคำสั่ง 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 Loop

โค้ด 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);
}

หากเงื่อนไขการตรวจสอบพบค่าที่ไม่รองรับ ฟังก์ชันตัวแฮนเดิลข้อผิดพลาด _handle_<API_name>_error จะสร้างขึ้นในไฟล์ 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);
}

แก้ไขข้อผิดพลาดของ API ที่รองรับเพียงบางส่วน

กำหนดฟังก์ชัน _handle_<API_name>_error เพื่อแทนที่ค่าที่ไม่รองรับ ด้วยวิธีแก้ปัญหาที่ยอมรับได้ตามความต้องการของคุณ

  1. เปิดโค้ด Apps Script ที่แปลงแล้วในตำแหน่งที่เกิดข้อผิดพลาด ดูค้นหาข้อผิดพลาด
  2. อ่านความคิดเห็นเหนือฟังก์ชันเพื่อทำความเข้าใจว่าค่าใดที่รองรับ และค่าใดที่ไม่รองรับ
  3. สำหรับค่าที่ไม่รองรับ ให้พิจารณาว่าค่าที่รองรับใดที่สามารถใช้แทนได้อย่างเหมาะสม
  4. อัปเดตฟังก์ชัน _handle_<API_name>_error เพื่อแสดงผลค่าที่รองรับแทน
  5. หากไม่พบวิธีแทนที่ค่าที่ไม่รองรับ คุณจะแปลง มาโครนี้ไม่ได้

ตัวอย่างข้อผิดพลาดของ API ที่รองรับเพียงบางส่วน

ตัวอย่างต่อไปนี้จะขยายความ API ของ VBA legend_position ที่กล่าวถึงข้างต้น ดูAPI ที่รองรับบางส่วน

ด้านล่างนี้เป็นตัวอย่างโค้ด VBA เดิมที่ใช้ค่าที่ไม่รองรับ xlLegendPositionCustom

Charts(1).Legend.Position = xlLegendPositionCustom

ตัวแปลงมาโครจะเพิ่มฟังก์ชันด้านล่างลงในไฟล์ unimplemented_constructs.gs

/**
* Throw error message for unsupported legend position.
* The VBA API Legend.Position which can take values xlLegendPositionTop,
* xlLegendPositionLeft, xlLegendPositionBottom, xlLegendPositionRight,
* xlLegendPositionCorner, xlLegendPositionCustom. It is partially supported in
* Apps Scripts that supports only a subset of the values (does not support
* xlLegendPositionCorner and xlLegendPositionCustom).
* @param {string} position
*/
function _handle_legend_position_error(position) {
// Please comment the throw statement and return a supported position value
// instead.
// Values that are supported here are xlLegendPositionTop,
// xlLegendPositionLeft, xlLegendPositionBottom, xlLegendPositionRight.
throw new Error(
   'Google Sheets does not support legend position: ' + position);
}

ต้องดำเนินการด้วยตนเอง

ต้องดำเนินการด้วยตนเองหมายความว่าสามารถแปลง VBA API เป็น Apps Script ได้ แต่ต้องมีวิธีแก้ปัญหา

ในรายงานความเข้ากันได้ที่คุณสร้างขึ้นก่อนการแปลง ประเภท API นี้จะติดป้ายกำกับว่ารองรับด้วยวิธีแก้ปัญหา

หากคุณไม่แก้ไข API ประเภทนี้ในโค้ด VBA ก่อนที่จะแปลงไฟล์ ลักษณะที่ปรากฏในโปรเจ็กต์ 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_<API_name>(param1, param2, ....) {
 ThrowException("API  not supported yet.");
}

แก้ไขข้อผิดพลาดที่ต้องดำเนินการด้วยตนเอง

ใช้การแก้ปัญหาชั่วคราวสำหรับ API เพื่อให้ API ทำงานได้ตามที่ต้องการ 1. เปิดโค้ด Apps Script ที่แปลงแล้วในตำแหน่งที่เกิดข้อผิดพลาด ดู ค้นหาข้อผิดพลาด 1. อ่านความคิดเห็นเหนือฟังก์ชันเพื่อทำความเข้าใจว่า API ใดที่ใช้สำหรับ วิธีแก้ปัญหาได้ 1. หากไม่พบวิธีแก้ปัญหาที่เหมาะสม ให้พิจารณานำ API ออกจากโค้ด 1. หากไม่พบวิธีแก้ปัญหาชั่วคราวหรือนำ API นี้ออกจากโค้ด และมาโคร แสดงข้อผิดพลาด คุณจะแปลงมาโครนี้ไม่ได้

ตัวอย่างข้อผิดพลาดที่ต้องดำเนินการด้วยตนเอง

ตัวอย่าง API ที่แสดงข้อผิดพลาด "ต้องดำเนินการด้วยตนเอง" และวิธีแก้ไขมีดังนี้

ตัวอย่างที่ 1: Autocorrect.Addreplacement

ในตัวอย่างต่อไปนี้ API ของ VBA 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() จะเปิดไฟล์ในเครื่องตามเส้นทางไฟล์

สมมติว่ามีไฟล์ 2 ไฟล์ที่เปิดโดย workbook.open() ในโค้ด VBA

  • ไฟล์ 1: C:\Data\abc.xlsx
  • ไฟล์ 2: C:\Data\xyz.xlsx

ด้านล่างนี้แสดงวิธีที่ตัวแปลงมาโครแทนที่ Workbook.open() ด้วย Apps Script ทุกที่ที่มีการใช้ Workbook.open() เพื่อเปิดไฟล์ 1

var spreadSheetId =
   _handle_mso_excel_get_google_spreadsheet_id("C:\Data\abc.xlsx");
var spreadSheet = SpreadsheetApp.openById(spreadSheetId);
ข้อผิดพลาดด้านล่างจะเพิ่มลงในไฟล์ unimplemented_constructs.gs ในโปรเจ็กต์ 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 '';
}

ตามที่ความคิดเห็นในตัวอย่างด้านบนแนะนำ คุณต้องแปลง ไฟล์เป้าหมายเป็นไฟล์ Google ชีตใน Google ไดรฟ์

รหัสสเปรดชีตใน Google ที่เกี่ยวข้องจะแสดงเป็นตัวหนาด้านล่าง

  • ไฟล์ #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 เพื่อเปิดไฟล์ตามรหัส ดังที่แสดงด้านล่าง

/**
* 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 โค้ดจะแสดงผลเป็น "ไม่กำหนด"

ตัวแปลงมาโครจะเพิ่มโค้ด 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));