תיקון שגיאות בקוד שהומר

התוסף 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 שלא ניתן היה להמיר באמצעות Macro Converter. סביר להניח שתצטרכו לשנות את הקובץ הזה כדי שהקוד יפעל באופן תקין.

לדוגמה: Window.Activate()

הדוגמה הבאה היא ממשק API לא נתמך שנקרא Window.Activate(). התוסף Macro Converter יוצר פונקציית 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().
  • לאובייקט אין ממשק API של Apps Script כדי לקבל את השם שלו.
  • אין אובייקט 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 שלא ניתן להמיר באמצעות Macro Converter מ-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 שלא יושם באמצעות ממשקי API קיימים של Apps Script או ספריות JS. לשם כך, בצע את הצעדים הבאים:

  1. פותחים את קוד Apps Script שהומר במיקום השגיאה. איתור שגיאות
  2. מעל הפונקציה, קוראים את התגובה שנוספה. במקרים מסוימים, התגובה כוללת הצעה להטמעת ה-API ב-Apps Script.
  3. אם לא מצאתם דרך להטמיע את ה-API ב-Apps Script, כדאי להסיר אותו מהקוד.
  4. אם לא מצאתם פתרון עקיף או להסיר את ה-API הזה מהקוד והמאקרו גורם לשגיאה הזו, לא תוכלו להמיר את המאקרו.

דוגמאות לשגיאות API שלא הוחלו

ריכזנו כאן דוגמאות לתרחישי API שלא הוחלו, והסבר איך לפתור אותם:

  • אין מקבילה ב-Apps Script: מוצגת דרך עקיפה לפתרון בעיה ב-Chart.Protect, ממשק API שלא קיים ב-Apps Script.
  • סוג אובייקט לא ידוע: כאן מוסבר איך לטפל בסוג אובייקט שהוא משתנה, ואיך להטמיע סוג אובייקט שאינו נתמך שאפשר ליצור מחדש ב-Apps Script.
דוגמה 1: אין קוד Apps Script מקביל או ממשק API לא ידוע

בדוגמה הזו, Chart.Protect לא הומר באופן אוטומטי כי אין דרך להגן על תרשים ב-Google Sheets.

/**
* 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. הדוגמה הבאה מרחיבה את הדוגמה שלמעלה ל-API של VBA name(). פרטים נוספים זמינים בכתובת variant_resolution.gs.

בדוגמה הזו תלמדו:

  1. איך ה-API של name() מומר לפונקציה חדשה בקובץ 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() שמפעילה את ה-API‏ name(). קוד ה-VBA מוצג כאן:

‘Defining a function that prints the name of the object in parameter
Sub PrintName(obj as Variant)
  Debug.Print obj.Name
End Sub
מכיוון ש-`name()` ‎ נקראת על אובייקט שהוא משתנה, סוג האובייקט לא ידוע לקוד המומר בזמן ההמרה. קוד הסקריפט של Apps שהומר יקרא לפונקציה '__handle_resolve_name':
function PrintName(obj) {
  Logger.log(_handle_resolve_name(obj));
}

3. נניח שקוד ה-VBA קורא לפונקציה PrintName() על סוג האובייקט CommandBar. קוד ה-VBA מוצג בהמשך:

PrintName Application.CommandBars.item("Standard")
אין תמיכה ב-CommandBar ב-Apps Script, וכתוצאה מכך גם אין תמיכה בשתי השיטות שבהן נעשה שימוש בקוד ה-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 מגדירים את שתי הפונקציות שנוצרו בקובץ 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.

מבנים ש-Macro Converter לא יכול להמיר נחשבים למבני שפה שלא הוחלו.

במקרים שבהם ממיר המאקרו קובע שקיים מבנה שפה שלא יושם, הוא מוסיף הערה מסוג 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 ויש כאלה שלא.

לדוגמה, ה-API של VBA‏ 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);
}

נדרש עבודה ידנית

המשמעות של נדרשת עבודה ידנית היא שאפשר להמיר את ה-API של VBA ל-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

בדוגמה הבאה, אפשר להמיר את Autocorrect.Addreplacement של VBA API, אבל צריך להשתמש בו כדי לעקוף את הבעיה. ב-Macro Converter מופיעות הצעות להטמעת הפונקציה בהערות לקוד.

/**
* 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()

ה-API של VBA‏ workbook.open() פותח קובץ מקומי על סמך נתיב קובץ.

נניח שיש שני קבצים שנפתחים על ידי workbook.open() בקוד ה-VBA:

  • קובץ 1: C:\Data\abc.xlsx
  • קובץ 2: C:\Data\xyz.xlsx

בהמשך מוסבר איך Macro Converter מחליף את 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 Sheets ב-Google Drive.

מזהי הגיליונות האלקטרוניים של 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.

כדי למנוע תוצאות בלתי צפויות, התוסף Macro Converter מוסיף קוד של 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));