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

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

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

  1. เปิดโค้ด Apps Script ที่แปลงแล้ว ณ ตำแหน่งที่เกิดข้อผิดพลาด ดูหัวข้อค้นหาข้อผิดพลาด
  2. อ่านความคิดเห็นที่เพิ่มไว้เหนือฟังก์ชัน ในบางกรณี ความคิดเห็นจะแนะนำวิธีใช้ API ใน Apps Script
  3. หากไม่พบวิธีใช้ API ใน Apps Script ให้ลองนำ API ออกจากโค้ด
  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()" ในออบเจ็กต์ที่เป็นตัวแปร โค้ดที่แปลงจึงไม่ทราบประเภทออบเจ็กต์ ณ เวลาที่เกิด Conversion โค้ด Apps Script ที่แปลงแล้วจะเรียกฟังก์ชัน `__handle_resolve_name` ดังนี้
function PrintName(obj) {
  Logger.log(_handle_resolve_name(obj));
}

3. สมมติว่าโค้ด VBA ของคุณเรียกใช้ฟังก์ชัน PrintName() ในประเภทออบเจ็กต์ CommandBar โค้ด VBA แสดงอยู่ด้านล่าง

PrintName Application.CommandBars.item("Standard")
Apps Script ไม่รองรับ CommandBar และด้วยเหตุนี้ ระบบจึงไม่รองรับเมธอด 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);
}

โครงสร้างภาษาที่ไม่ได้ใช้งาน

คอนสตรัคต์คือองค์ประกอบของภาษาโค้ดที่ควบคุมขั้นตอนการดำเนินการหรือการแสดงข้อมูล เช่น ลูป ป้ายกำกับ เหตุการณ์ และ gotos รายการคอนสตรัคต์ VBA ทั้งหมดมีดังนี้

โครงสร้างที่เครื่องมือแปลงมาโครแปลงไม่ได้จะถือว่าไม่ได้ใช้งาน โครงสร้างภาษา

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

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

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

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

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

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

เช่น 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 ที่รองรับบางส่วน

ตัวอย่างต่อไปนี้จะขยายความเกี่ยวกับ VBA API 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

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

สมมติว่า workbook.open() เปิดไฟล์ 2 ไฟล์ในโค้ด 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 โค้ดจะแสดงผลเป็น "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));