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

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

כשסוג האובייקט לא נקבע, הכלי להמרת מאקרו יוצר פונקציה חדשה שנקראת __handle_resolve_name בקובץ variant_resolutions.gs.

לפניכם דוגמה בקוד:

קוד VBA מקורי

a = Selection.name

במקרה הזה, ה-API name() יופעל בבחירה הנוכחית. הבחירה יכולה להיות אובייקט Sheets או אובייקט צורה. אם מדובר באובייקט של Sheets, התרגום הוא 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 כפונקציות ריקות (לפעמים עם חתימות ריקות). אם לא ניתן היה לזהות את סוג האובייקט, יכול להיות שבמקום זאת יתווסף לקובץ variant_resolution.gs את ה-API שלא הוטמע.

בדוח התאימות שיצרתם לפני ההמרה, ה-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_(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. הדוגמה הבאה מרחיבה לגבי הדוגמה של VBA name() API שלמעלה. variant_resolution.gs

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

  1. איך ה-API של name() עובר המרה לפונקציה חדשה בקובץ variant_resolution.gs.
  2. איך הפונקציה החדשה נקראת בקוד שהומר.
  3. כיצד ליצור ב-Apps Script פתרון חלופי עבור 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")
ב-Apps Script אין תמיכה ב-CommandBar, ולכן גם שתי השיטות (method) שנעשה בהן שימוש בקוד ה-VBA שצוינו למעלה לא נתמכות.
  • Application.CommandBars(): ב-VBA, הפונקציה הזו מחזירה רשימה של כל CommandBar האובייקטים.
  • CommandBars.item(): ב-VBA, הפעולה הזו מחזירה אובייקט CommandBar ספציפי.
סוג האובייקט הזה לא נתמך ב-Apps Script, לכן הקוד לאחר ההמרה יוצר את הפונקציות הבאות בקובץ 'unembeded_constructs.gs' שצריך להגדיר.
  • _api_application_commandbars()
  • _api_commandbars_item()
הפונקציות מופעלות בקוד שהומר, כמו בדוגמה הבאה:
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.');
}

כדי להפעיל את הפונקציות החדשות:

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

מבני שפה לא מיושמים

construct הוא רכיב בשפת הקוד שקובע את תהליך הביצוע או את הצגת הנתונים. לדוגמה, לולאות, תוויות, אירועים וגוטו. כאן יש רשימה של כל המבנים של VBA.

מבנים שממיר מאקרו לא יכול להמיר נחשבים למבני שפה לא מיושמים.

כאשר ממיר המאקרו קובע שקיים מבנה שפה לא מיושם, הוא מוסיף תגובת TODO.

מבני VBA הבאים לא נתמכים:

תיקון שגיאות במבנה שפה לא מוטמע

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

דוגמאות לשגיאות במבנה שפה לא מיושם

אחד ממבני השפה הלא מיושמים הנפוצים ביותר הוא הצהרה GoTo. אפשר להחליף הצהרות GoTo של VBA בלולאות. בהמשך מופיעות שתי דוגמאות לשימוש בלולאות במקום בהצהרות 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 בלולאת עבור

קוד 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);
}

אם תנאי התיקוף ימצא אחד מהערכים שלא נתמכים, נוצרת פונקציית handler של שגיאות _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_(param1, param2, ....) {
 ThrowException("API  not supported yet.");
}

תיקון שגיאות שצריך להגיש ידנית

מטמיעים פתרון עקיף כדי שה-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.');

}

ההטמעה של ה-API Autocorrect.Addreplacement מוצגת כאן:

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() בקוד 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 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, הקוד מחזיר קוד לא מוגדר.

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