خطاهای کد تبدیل شده خود را برطرف کنید

افزونه 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() است. Macro Converter یک تابع Apps Script جدید با نام مشابه ایجاد می کند و آن را در فایل unimplemented_constructs.gs تعریف می کند. از آنجایی که تابع VBA پشتیبانی نمی شود، تابع جدید Apps Script یک استثنا ایجاد می کند.

عملکرد جدید به کد Apps Script تبدیل شده در همه جاهایی که API اصلی در کد VBA استفاده شده است اضافه می شود.

اگر راه حلی برای ایجاد مجدد رفتار API اصلی پیدا کردید، فقط باید تعریف تابع را در فایل unimplemented_constructs.gs به روز کنید. هنگامی که تابع در آنجا تعریف شد، در هر جایی که تابع در پروژه Apps Script شما ظاهر می شود اعمال می شود.

این مثال در کد است:

کد VBA اصلی

Window.activate()

کد برنامه‌های اسکریپت تبدیل‌شده، اضافه شده در خط

_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 که دارای چندین نوع بازگشت است یا اینکه شی به عنوان یک نوع خود اعلام می شود.

Macro Converter یک تابع جدید به نام __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

در این مورد، name() API در انتخاب فعلی فراخوانی می شود. انتخاب می تواند یک شی Sheet یا یک شی Shape باشد. اگر یک شی Sheet باشد، ترجمه getName() است، اما اگر یک شی Shape باشد، در 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_(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: اسکریپت برنامه های معادل یا 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. نحوه ایجاد یک راه حل برای 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 پشتیبانی نمی شود و در نتیجه، دو روش استفاده شده در کد 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")))

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

ساختارهای زبانی اجرا نشده

سازه عنصری از زبان کد است که جریان اجرا یا نمایش داده را کنترل می کند. به عنوان مثال، حلقه ها، برچسب ها، رویدادها و gotos. در اینجا لیستی از تمام ساختارهای VBA آمده است.

ساختارهایی که مبدل ماکرو نمی تواند آنها را تبدیل کند، ساختارهای زبانی اجرا نشده در نظر گرفته می شوند.

در جایی که مبدل ماکرو تشخیص می دهد که یک ساختار زبانی اجرا نشده وجود دارد، یک نظر 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
کد برنامه اسکریپت معادل
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
کد برنامه اسکریپت معادل
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 برای تعریف افسانه در یک نمودار اکسل استفاده می شود. از چندین نوع مقادیر ورودی پشتیبانی می کند، از جمله:

  • 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_(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() در کد 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، کد تعریف نشده برمی گردد.

برای جلوگیری از نتایج غیرمنتظره، Macro Converter کد Apps Script را اضافه می‌کند که در صورت تلاش برای دسترسی به عناصر فراتر از محدوده یک آرایه، یک استثنا ایجاد می‌کند.

این مثال در کد زیر نشان داده شده است:

کد VBA اصلی
Dim arr
arr = Array("apple", "orange")
MsgBox arr(5)
Will throw the following error:
Subscript out of range
کد اسکریپت برنامه های تبدیل شده (قبل از اضافه شدن خطای استثنا)
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));