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

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

از این راهنما برای درک فایل‌های اسکریپت برنامه‌ها (فایل‌های GS) اضافه شده به پروژه خود، تفسیر انواع مختلف خطا و یادگیری نحوه رفع خطاها استفاده کنید.

درک فایل‌های اسکریپت برنامه‌ها که به پروژه شما اضافه شده‌اند

فایل‌های 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()

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

_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

در این حالت، تابع 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 با خطایی مواجه می‌شوید، پیام نوع خطا و محل آن را مشخص می‌کند. قالب پیام خطا بستگی به این دارد که از کدام Runtime مربوط به Apps Script استفاده می‌کنید.

اگر در زمان اجرای پیش‌فرض V8 هستید، خطایی مانند خطای زیر مشاهده خواهید کرد:

_api_windows_active (unimplemented_constructs:2:3)

این یعنی خطا در فایل unimplemented_constructs.gs و در خط ۲، کاراکتر ۳ قرار دارد.

اگر در محیط اجرایی منسوخ‌شده‌ی راینو هستید، خطایی مانند خطای زیر مشاهده خواهید کرد:

unimplemented_constructs:2 (_api_windows_active)

این یعنی خطا در فایل unimplemented_constructs.gs و در خط ۲ قرار دارد.

انواع خطا

شما می‌توانید اکثر خطاهایی که در فایل‌های unimplemented_constructs.gs و variant_resolution.gs که در بالا توضیح داده شد، با آنها مواجه می‌شوید را برطرف کنید.

انواع خطاهایی که ممکن است با آنها مواجه شوید عبارتند از:

API پیاده‌سازی نشده

یک API پیاده‌سازی نشده، APIای است که مبدل ماکرو نمی‌تواند آن را از VBA به Apps Script تبدیل کند و هیچ راه حل جایگزین شناخته شده‌ای برای آن API وجود ندارد.

APIهای پیاده‌سازی نشده معمولاً به صورت توابع خالی - گاهی اوقات با امضاهای خالی - به فایل unimplemented_constructs.gs اضافه می‌شوند. اگر نوع شیء قابل تعیین نباشد، API پیاده‌سازی نشده ممکن است به جای آن به فایل variant_resolution.gs اضافه شود.

در گزارش سازگاری که قبل از تبدیل ایجاد کرده‌اید، این API با عنوان « نیاز به بررسی بیشتر» برچسب‌گذاری شده است.

اگر قبل از تبدیل فایل، این نوع API را در کد VBA خود اصلاح نکنید، در پروژه Apps Script به این شکل نمایش داده می‌شود:

/**
* Could not convert . Please add relevant code in the following
* function to implement it.
* This API has been used at the following locations in the VBA script.
*      : 
* We couldn't find an equivalent API in Apps Script for this VBA API. Please
* reconsider if this function call is critical, otherwise consider implementing
* it in a different way.
* @param param1 {}
* @param param2 {}
* ...
* @return {}
*/
function _api_<API_name>(param1, param2, ....) {
  ThrowException("API  not supported yet.");
}

رفع خطاهای API پیاده‌سازی نشده

API پیاده‌سازی نشده را با APIهای Apps Script یا کتابخانه‌های JS موجود تعریف کنید. برای انجام این کار، این مراحل را دنبال کنید:

  1. کد اسکریپت برنامه‌ها (Apps Script) تبدیل‌شده را در محل خطا باز کنید. به بخش یافتن خطاها (Find errors) مراجعه کنید.
  2. بالای تابع، توضیحاتی که اضافه شده را بخوانید. در برخی موارد، توضیحات نحوه پیاده‌سازی API در Apps Script را پیشنهاد می‌دهند.
  3. اگر نمی‌توانید راهی برای پیاده‌سازی API در Apps Script پیدا کنید، حذف آن از کد خود را در نظر بگیرید.
  4. اگر نمی‌توانید راه حلی پیدا کنید یا این API را از کد خود حذف کنید و ماکروی شما این خطا را می‌دهد، نمی‌توانید این ماکرو را تبدیل کنید.

نمونه‌هایی از خطاهای API پیاده‌سازی نشده

در اینجا نمونه‌هایی از سناریوهای API پیاده‌سازی نشده و نحوه رفع آنها آورده شده است:

  • معادلی برای Apps Script وجود ندارد : یک راه حل غیرمستقیم برای Chart.Protect نشان می‌دهد، API که در Apps Script وجود ندارد.
  • یک نوع شیء ناشناخته : نحوه مدیریت یک نوع شیء که یک متغیر است و نحوه پیاده‌سازی یک نوع شیء پشتیبانی نشده که می‌تواند در Apps Script بازسازی شود را نشان می‌دهد.
مثال ۱: هیچ اسکریپت معادلی برای 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();
}
}
مثال ۲: نوع شیء پشتیبانی نشده

وقتی نوع شیء ناشناخته باشد، خطای API پیاده‌سازی نشده به فایل variant_resolution.gs اضافه می‌شود. مثال زیر، مثال API name() در بالا را بسط می‌دهد. به variant_resolution.gs مراجعه کنید.

در این مثال، شما یاد خواهید گرفت:

  1. نحوه تبدیل API name() به یک تابع جدید در فایل variant_resolution.gs .
  2. نحوه فراخوانی تابع جدید در کد تبدیل شده .
  3. چگونه می‌توان در Apps Script یک راه حل برای CommandBar ، یک نوع شیء پشتیبانی نشده، ایجاد کرد .

۱. از آنجایی که کد تبدیل‌شده نمی‌تواند نوع دقیق شیء که 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;
}

۲. فرض کنید کد 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 Script تبدیل‌شده، تابع `__handle_resolve_name` را فراخوانی خواهد کرد:
function PrintName(obj) {
  Logger.log(_handle_resolve_name(obj));
}

۳. فرض کنید کد 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.');
}

برای اینکه بتوانید از توابع جدید استفاده کنید، مراحل زیر را انجام دهید:

۳.۱ یک نوع شیء جدید تعریف کنید که قابلیت‌های CommandBars و مجموعه‌ای جدید از CommandBars را مشابه آنچه در VBA وجود دارد، ایجاد کند.

۳.۲ یک متد getName() برای نوع شیء جدید اضافه کنید.

مراحل ۳.۱ و ۳.۲ در کد زیر نشان داده شده است. اشیاء منو به عنوان یک نوع شیء جدید ایجاد می‌شوند که رفتار 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();

۳.۳ تابع __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;
}

۳.۴ دو تابع ایجاد شده در فایل unimplemented_constructs.gs ( _api_application_commandbars() و _api_commandbars_item() ) را تعریف کنید. این مرحله تضمین می‌کند که فراخوانی‌های اصلی تابع کار می‌کنند.

//This is straightforward based on the implementation of a CommandBar and the
// CommandBars collection above:
function _api_application_commandbars(CallingObject) {
 return GlobalCommandBars;
}
function _api_commandbars_item(CallingObject, index) {
 return CallingObject.getCommandBar(index);
}

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

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

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

در جایی که مبدل ماکرو تشخیص می‌دهد که یک ساختار زبانی پیاده‌سازی نشده وجود دارد، یک کامنت TODO درج می‌کند.

ساختارهای VBA زیر پشتیبانی نمی‌شوند:

خطاهای ساختار زبان پیاده‌سازی نشده را برطرف کنید

  1. کد خود را به‌روزرسانی کنید تا منطق شما به ساختار زبان پشتیبانی نشده متکی نباشد.
  2. کد اسکریپت برنامه‌ها (Apps Script) تبدیل‌شده را در محل خطا باز کنید. به بخش یافتن خطاها (Find errors) مراجعه کنید.
  3. بر اساس منطق کد، آن را به گونه‌ای به‌روزرسانی کنید که نیازی به ساختار زبان پشتیبانی نشده نداشته باشد.
  4. اگر نمی‌توانید راهی برای بازنویسی کد خود بدون ساختار زبان پشتیبانی نشده پیدا کنید، نمی‌توانید این ماکرو را تبدیل کنید.

نمونه‌هایی از خطاهای ساختار زبان پیاده‌سازی نشده

یکی از رایج‌ترین ساختارهای زبانی پیاده‌سازی نشده، دستور GoTo است. می‌توانید برخی از دستورات GoTo در VBA را با حلقه‌ها جایگزین کنید. در زیر دو مثال از استفاده از حلقه‌ها به جای دستورات GoTo آورده شده است.

مثال ۱: جایگزین کردن 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);
}

مثال ۲: جایگزین کردن 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 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) تبدیل‌شده را در محل خطا باز کنید. به بخش یافتن خطاها (Find errors) مراجعه کنید.
  2. برای اینکه بفهمید کدام مقادیر پشتیبانی می‌شوند و کدام‌ها پشتیبانی نمی‌شوند، کامنت بالای تابع را بخوانید.
  3. برای مقادیر پشتیبانی نشده، تعیین کنید که کدام مقادیر پشتیبانی شده می‌توانند به عنوان جایگزین مناسب عمل کنند.
  4. تابع _handle_<API_name>_error به‌روزرسانی کنید تا به جای آن، یک مقدار پشتیبانی‌شده را برگرداند.
  5. اگر نتوانید راهی برای جایگزینی مقدار پشتیبانی نشده پیدا کنید، نمی‌توانید این ماکرو را تبدیل کنید.

مثالی از خطای API که تا حدی پشتیبانی می‌شود

مثال زیر، تابع legend_position در VBA API که در بالا ذکر شد را بسط می‌دهد. به بخش «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 طبق برنامه کار کند. ۱. کد Apps Script تبدیل شده را در محل خطا باز کنید. به بخش یافتن خطاها مراجعه کنید. ۱. کامنت بالای تابع را بخوانید تا بفهمید از کدام APIها می‌توان برای یک راه حل موقت استفاده کرد. ۱. اگر نمی‌توانید یک راه حل موقت مناسب پیدا کنید، حذف API را از کد خود در نظر بگیرید. ۱. اگر نمی‌توانید یک راه حل موقت پیدا کنید یا این API را از کد خود حذف کنید و ماکروی شما خطا می‌دهد، نمی‌توانید این ماکرو را تبدیل کنید.

نمونه‌هایی از خطاهای نیازمند کار دستی

در اینجا نمونه‌هایی از APIهایی که خطاهای Manual work needed را نشان می‌دهند و نحوه رفع آنها آورده شده است:

مثال ۱: Autocorrect.Addreplacement

در مثال زیر، تابع Autocorrect.Addreplacement در VBA API قابل تبدیل است، اما به یک راه حل موقت نیاز دارد. مبدل ماکرو نحوه پیاده‌سازی تابع را در توضیحات کد پیشنهاد می‌دهد.

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

مثال ۲: Workbook.open()

workbook.open() در VBA API، یک فایل محلی را بر اساس مسیر فایل باز می‌کند.

فرض کنید دو فایل توسط workbook.open() در کد VBA باز می‌شوند:

  • فایل ۱: C:\Data\abc.xlsx
  • فایل ۲: C:\Data\xyz.xlsx

شکل زیر نشان می‌دهد که چگونه مبدل ماکرو Workbook.open() را در هر جایی که Workbook.open() برای باز کردن فایل ۱ استفاده می‌شود، با Apps Script جایگزین می‌کند:

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 تبدیل کنید.

شناسه‌های مربوط به صفحات گسترده گوگل در زیر پررنگ شده‌اند:

  • فایل شماره ۱: C:\Data\abc.xlsx تبدیل می‌شود به https://docs.google.com/spreadsheets/d/ abc123Abc123Abc123abc
  • فایل شماره ۲: 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
کد اسکریپت برنامه‌های تبدیل‌شده (قبل از اضافه شدن خطای استثنا)
var arr;
arr = ["apple", "orange"];
Browser.msgBox(arr[5]);
Will return this value and not throw an error:
undefined
کد اسکریپت برنامه‌ها برای نمایش خطای استثنا اضافه شد.
/**
* 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));