إصلاح الأخطاء في الرمز الذي تم تحويله

تعمل إضافة Macro Converter على أتمتة معظم عملية التحويل، ولكن قد تحتاج إلى إجراء تعديلات على بعض واجهات برمجة التطبيقات وعناصر أخرى لإكمال الرمز البرمجي.

استخدِم هذا الدليل للتعرّف على ملفات Apps Script (ملفات GS) المُضافة إلى مشروعك، وتفسير أنواع الأخطاء المختلفة، ومعرفة كيفية حلّ الأخطاء.

التعرّف على ملفات "برمجة تطبيقات Google" المُضافة إلى مشروعك

تتم إضافة ملفات GS إضافية إلى مشروع "برمجة تطبيقات Google" للمساعدة في:

  • تحديد الثوابت والقيم في لغة VBA التي لا تتوفّر في "برمجة التطبيقات"
  • تنفيذ واجهات برمجة التطبيقات التي لم يتم تحويلها
  • حلّ خيارات المنتج

تتم إضافة ملفات GS التالية إلى مشروع "برمجة تطبيقات Google":

  • Library.gs
  • Unimplemented_constructs.gs
  • Variant_resolutions.gs

Library.gs

بشكل عام، ليس عليك تعديل أي شيء في ملف library.gs.

يحدّد الملف library.gs الدوال والثوابت التي تم استخدامها في رمز VBA الخاص بك والتي لا تتوفّر في "برمجة تطبيقات Google". يساعد ذلك في أن يشبه رمز Apps Script الجديد رمز VBA بشكل أفضل. بالإضافة إلى ذلك، لا تحتاج إلى تكرار التعريفات في كل مرة يتم فيها استخدام الدوال أو الثوابت من ملف library.gs.

Unimplemented_constructs.gs

يتناول ملف unimplemented_constructs.gs بنيات أو واجهات برمجة تطبيقات تعذّر على "أداة تحويل الماكرو" تحويلها. من المحتمل أن تحتاج إلى تعديل هذا الملف لجعل الرمز البرمجي يعمل على النحو المنشود.

مثلاً: Window.Activate()

في ما يلي مثال على واجهة برمجة تطبيقات غير متوافقة باسم Window.Activate(). تنشئ "أداة تحويل وحدات الماكرو" دالة جديدة في "برمجة تطبيقات Google" باسم مشابه وتعرّفها في الملف unimplemented_constructs.gs. بما أنّ دالة VBA غير متاحة، ستعرض دالة Apps Script الجديدة استثناءً.

تتم إضافة الدالة الجديدة إلى رمز Apps Script المحوَّل في كل مكان تم فيه استخدام واجهة برمجة التطبيقات الأصلية في رمز VBA.

إذا عثرت على حل بديل لإعادة إنشاء سلوك واجهة برمجة التطبيقات الأصلية، ما عليك سوى تعديل تعريف الدالة في ملف unimplemented_constructs.gs. بعد تعريف الدالة هناك، يتم تطبيقها في كل مكان تظهر فيه الدالة في مشروع "برمجة التطبيقات".

في ما يلي المثال في الرمز:

رمز VBA الأصلي

Window.activate()

رمز "برمجة تطبيقات Google" المحوّل، تمت إضافته في السطر

_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 إلى مشروع "برمجة التطبيقات" إذا تعذّر تحديد نوع أحد العناصر. يمكن أن يحدث ذلك لعدة أسباب، مثل أن يكون لواجهة برمجة التطبيقات عدة أنواع إرجاع أو أن يكون العنصر معرَّفًا كنوع متغير.

يضيف Macro Converter دالة جديدة إلى هذا الملف باسم __handle_resolve_<api>() تحلّ محل واجهة برمجة التطبيقات المعنيّة وتساعد في تحديد نوع العنصر.

في بعض الحالات، قد تحتاج إلى تعديل الدالة __handle_resolve_<api>() لتحديد نوع العنصر يدويًا. اطّلِع على نوع العنصر غير المتاح.

مثلاً: name()

تحدّد العديد من أنواع الكائنات في VBA واجهة برمجة تطبيقات name(). عادةً، يكون الرمز المكافئ في Apps Script هو getName()، ولكن ليس لكل نوع من أنواع العناصر. يمكن أن تحدث حالات بديلة متعددة:

  • يختلف اسم واجهة برمجة التطبيقات المكافئة للعنصر عن getName().
  • لا يتضمّن العنصر واجهة برمجة تطبيقات Apps Script للحصول على اسمه.
  • لا يتوفّر عنصر مكافئ في "برمجة التطبيقات".

عندما يتعذّر تحديد نوع العنصر، ينشئ Macro Converter دالة جديدة باسم __handle_resolve_name في الملف variant_resolutions.gs.

في ما يلي المثال في الرمز:

رمز VBA الأصلي

a = Selection.name

في هذه الحالة، يتم استدعاء واجهة برمجة التطبيقات name() على التحديد الحالي. يمكن أن يكون التحديد كائن ورقة أو كائن شكل. إذا كان كائن Sheet، تكون الترجمة getName()، ولكن إذا كان كائن Shape، لا يوجد مكافئ في "برمجة تطبيقات Google".

رمز "برمجة تطبيقات Google" المحوّل، تمت إضافته في السطر

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 الموضّحَين أعلاه.

تشمل أنواع الأخطاء التي قد تواجهها ما يلي:

واجهة برمجة تطبيقات غير منفَّذة

واجهة برمجة التطبيقات غير المتاحة هي واجهة برمجة تطبيقات لا يمكن لـ "محوّل الماكرو" تحويلها من VBA إلى "برمجة التطبيقات"، ولا يتوفّر حل بديل معروف لها.

عادةً ما تتم إضافة واجهات برمجة التطبيقات غير المنفَّذة كدوال فارغة، وأحيانًا مع توقيعات فارغة، إلى الملف unimplemented_constructs.gs. إذا تعذّر تحديد نوع العنصر، قد تتم إضافة واجهة برمجة التطبيقات غير المنفَّذة إلى الملف variant_resolution.gs بدلاً من ذلك.

في تقرير التوافق الذي أنشأته قبل عملية التحويل، تم تصنيف واجهة برمجة التطبيقات هذه على أنّها تتطلّب المزيد من البحث.

إذا لم يتم إصلاح هذا النوع من واجهات برمجة التطبيقات في رمز VBA قبل تحويل الملف، سيظهر على النحو التالي في مشروع "برمجة تطبيقات Google":

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

إصلاح أخطاء واجهة برمجة التطبيقات غير المنفَّذة

حدِّد واجهة برمجة التطبيقات غير المنفَّذة باستخدام واجهات برمجة التطبيقات الحالية في "برمجة التطبيقات" أو مكتبات JavaScript. لإجراء هذا، اتبع هذه الخطوات:

  1. افتح رمز Apps Script المحوَّل في مكان الخطأ. يُرجى الاطّلاع على العثور على الأخطاء.
  2. اطّلِع على التعليق الذي تمت إضافته فوق الدالة. في بعض الحالات، يقترح التعليق كيفية تنفيذ واجهة برمجة التطبيقات في "برمجة تطبيقات Google".
  3. إذا لم تتمكّن من العثور على طريقة لتنفيذ واجهة برمجة التطبيقات في "برمجة تطبيقات Google"، ننصحك بإزالتها من الرمز.
  4. إذا لم تتمكّن من العثور على حلّ بديل أو إزالة واجهة برمجة التطبيقات هذه من الرمز البرمجي وظهر هذا الخطأ في وحدة الماكرو، لن تتمكّن من تحويل وحدة الماكرو هذه.

أمثلة على أخطاء واجهة برمجة التطبيقات غير المنفَّذة

في ما يلي أمثلة على سيناريوهات واجهة برمجة التطبيقات غير المنفَّذة وكيفية إصلاحها:

  • لا يتوفّر مكافئ في "برمجة تطبيقات Google": تعرض هذه السمة حلاً بديلاً غير مباشر لـ Chart.Protect، وهي واجهة برمجة تطبيقات غير متوفّرة في "برمجة تطبيقات Google".
  • نوع عنصر غير معروف: يوضّح هذا القسم كيفية التعامل مع نوع عنصر يمثّل متغيّرًا، وكيفية تنفيذ نوع عنصر غير متوافق يمكن إعادة إنشائه في &quot;برمجة تطبيقات Google&quot;.
المثال 1: عدم توفّر واجهة برمجة تطبيقات مكافئة أو غير معروفة في "برمجة تطبيقات Google"

في هذا المثال، لم يتم تحويل Chart.Protect تلقائيًا لأنّه لا يمكن حماية رسم بياني في "جداول بيانات Google".

/**
* Could not convert chart.protect API. Please add relevant code in the following
* function to implement it.
*
* This API has been used at the following locations in the VBA script.
*     sheet1 : line 3
* You can use the following Apps Script APIs to convert it.
*
* Comments : Auto conversion of Chart.Protect is not supported yet. If the API is
* critical for the workflow the user can implement the unimplemented handler
* method in the generated code, else comment out the throw statement.
*
* @param {Object} CallingObject represents the parent object using which the API
* has been called.
* @param {string} Password
* @param {boolean} DrawingObjects
* @param {boolean} Contents
* @param {boolean} Scenarios
* @param {boolean} UserInterfaceOnly
*
*/
function _api_chart_protect(
   CallingObject, Password, DrawingObjects, Contents, Scenarios,
   UserInterfaceOnly) {
 ThrowException('API chart.protect not supported yet.');
}
على الرغم من أنّه لا يمكنك حماية مخطط، يمكنك حماية نطاق البيانات الخاص بالمخطط حتى لا يمكن تغيير البيانات.

في ما يلي مثال على تنفيذ حماية النطاق:
/**
* Could not convert chart.protect API. Please add relevant code in the following
* function to implement it.
* This API has been used at the following locations in the VBA script.
*     sheet1 : line 3
*
* You can use the following Apps Script APIs to convert it.
* Comments : Auto conversion of Chart.Protect is not supported yet. If the API
* is critical for the workflow the user can implement the unimplemented handler
* method in the generated code, else comment out the throw statement.
*
* @param {Object} CallingObject represents the parent object using which the API
* has been called.
* @param {string} Password
* @param {boolean} DrawingObjects
* @param {boolean} Contents
* @param {boolean} Scenarios
* @param {boolean} UserInterfaceOnly
*/
function _api_chart_protect(
  CallingObject, Password, DrawingObjects, Contents, Scenarios, UserInterfaceOnly) {
var ranges = CallingObject.getChart().getRanges();
for (var i = 0; i < ranges.length; i++) {
  // Note that this does not lock the range for the document owner.
  ranges[i].protect();
}
}
المثال 2: نوع العنصر غير متاح

عندما يكون نوع العنصر غير معروف، تتم إضافة خطأ واجهة برمجة التطبيقات غير المنفَّذة إلى الملف variant_resolution.gs. يقدّم المثال التالي تفاصيل إضافية عن مثال واجهة برمجة التطبيقات name() VBA أعلاه. يمكنك الاطّلاع على variant_resolution.gs.

في هذا المثال، ستتعرّف على ما يلي:

  1. كيفية تحويل واجهة برمجة التطبيقات name() إلى دالة جديدة في ملف variant_resolution.gs
  2. كيفية استدعاء الدالة الجديدة في الرمز البرمجي المحوَّل
  3. كيفية إنشاء حلّ بديل لـ CommandBar، وهو نوع عنصر غير متوافق، في "برمجة التطبيقات"

1. بما أنّ الرمز المحوّل لا يمكنه تحديد نوع العنصر الدقيق الذي يتم استدعاؤه، ينشئ Macro Converter دالة جديدة باسم __handle_resolve_name، كما هو موضّح أدناه.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(). يظهر رمز 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 مع "برمجة تطبيقات Google"، وبالتالي لا تتوافق الطريقتان المستخدَمتان في رمز VBA أعلاه أيضًا.
  • Application.CommandBars(): في VBA، تعرض هذه الدالة قائمة بجميع عناصر CommandBar.
  • CommandBars.item(): في VBA، تعرض هذه الدالة عنصر CommandBar معيّنًا.
بما أنّ نوع العنصر هذا غير متوافق مع Apps Script، ينشئ الرمز البرمجي المحوَّل الدوال التالية في الملف `unimplemented_constructs.gs` الذي عليك تحديده.
  • _api_application_commandbars()
  • _api_commandbars_item()
يتم استدعاء الدوال في الرمز البرمجي المحوَّل كما هو موضّح أدناه:
PrintName(_api_commandbars_item(_api_application_commandbars(), "Standard")))

Heres how the new functions are added to the unimplemented_construct.gs file:

function _api_application_commandbars(CallingObject) {
  ThrowException('API application.commandbars not supported yet.');
}
function _api_commandbars_item(CallingObject, index) {
  ThrowException('API commandbars.item not supported yet.');
}

للاستفادة من الوظائف الجديدة، اتّبِع الخطوات التالية:

‫3.1 حدِّد نوع عنصر جديدًا ينشئ وظائف CommandBars ومجموعة جديدة من CommandBars مشابهة لما هو متوفّر في VBA.

‫3.2 أضِف طريقة getName() لنوع العنصر الجديد.

يتم عرض الخطوتين 3.1 و3.2 في الرمز أدناه. يتم إنشاء عناصر القائمة كنوع جديد من العناصر يحاكي سلوك CommandBars.

// Our Implementation of CommandBar using Menu objects.

function CommandBar(name) {
  this.name = name;
  // Create a menu object to represent the commandbar.
  this.menu = SpreadsheetApp.getUi().createMenu(name);
  // Create methods for retrieving or updating the name of the object
  this.getName = function() {
    return this.name;
  };
  this.updateName = function(name) {
    this.name = name;
  };
  // ========================================================================
  // Implement other methods of CommandBar objects that are used in the script.
  // =====================================================================
  return this;
}
// Our implementation of the collection of CommandBars that exists in VBA
function CommandBars() {
  this.commandBars = [];
  this.getCommandBar = function(name) {
    for (var i = 0; i < this.commandBars.length; i++) {
      if (!this.commandBars[i].getName() == name) {
        return this.commandBars[i];
      }
    }
    // No commandBar with the name exists, create a new one and return.
    var commandBar = new CommandBar(name);
    this.commandBars.push(commandBar);
    return commandBar;
  };
  return this;
}
// Create a global object that represents CommandBars collection.
var GlobalCommandBars = new CommandBars();

‫3.3 عدِّل الدالة __handle_resolve_name في الملف variant_resolution.gs للتعامل مع نوع العنصر الجديد. أضِف قسمًا إلى الدالة، كما هو موضّح أدناه:

function __handle_resolve_name(ExecutionContext, CallingObject, params_map) {
 var found_api_variant = false;
 var return_value;
 if (String(CallingObject) == "Sheet") {
   if (!ExecutionContext.isLhs) {
     return_value = CallingObject.getName();
     found_api_variant = true;
   }
 }
 if (CallingObject instanceof ChartInSheet) {
   if (!ExecutionContext.isLhs) {
     return_value = CallingObject.getName();
     found_api_variant = true;
   }
 }
 // New section added below
 // ========================================================================
 if (CallingObject instanceof CommandBar) {
   objectExtend(params_map, {VALUETOSET: params_map.param0});
   if (ExecutionContext.isLhs) {
     // Call the setter method.
     CallingObject.updateName(params_map.VALUETOSET);
     found_api_variant = true;
   } else {
     // Getter is called, return the commandbar name,
     return_value = CallingObject.getName();
     found_api_variant = true;
   }
 }
 // ========================================================================
 // New section added above
 if (!found_api_variant) {
   ThrowException('API .name not supported yet.');
 }
 return return_value;
}

‫3.4 حدِّد الدالتَين اللتين تم إنشاؤهما في الملف unimplemented_constructs.gs(_api_application_commandbars()، _api_commandbars_item()). تضمن هذه الخطوة عمل عمليات الاستدعاء الأصلية للدالة.

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

بُنى لغوية غير منفَّذة

البنية هي عنصر من عناصر لغة الترميز يتحكّم في مسار التنفيذ أو عرض البيانات. على سبيل المثال، الحلقات والتصنيفات والأحداث وعمليات الانتقال. إليك قائمة بجميع بنى VBA.

تُعدّ البُنى التي لا يمكن للمحوّل الكلي تحويلها بُنى لغوية غير منفَّذة.

عندما يحدّد Macro Converter أنّ هناك بنية لغوية غير منفَّذة، يدرج تعليق TODO.

لا تتوافق بنى VBA التالية:

إصلاح أخطاء بنية اللغة غير المتوافقة

  1. عدِّل الرمز البرمجي لكي لا تعتمد منطقته على بنية اللغة غير المتوافقة.
  2. افتح رمز Apps Script المحوَّل في مكان الخطأ. راجِع العثور على الأخطاء.
  3. استنادًا إلى منطق الرمز، عدِّله بطريقة لا تتطلّب بنية اللغة غير المتوافقة.
  4. إذا لم تتمكّن من العثور على طريقة لإعادة كتابة الرمز بدون بنية اللغة غير المتوافقة، لن تتمكّن من تحويل هذا الماكرو.

أمثلة على أخطاء بنية اللغة غير المنفَّذة

من بين بنى اللغة غير المطبَّقة الأكثر شيوعًا عبارة GoTo. يمكنك استبدال بعض عبارات VBA GoTo بحلقات. في ما يلي مثالان على استخدام الحلقات بدلاً من عبارات GoTo.

المثال 1: استبدال GoTo بـ While Loop

رمز VBA الأصلي
Sub Test()
 a = 0
 start: Debug.Print a
 While a < 100
   a = a + 1
   If a Mod 3 == 0
     Goto start
   End If
 Wend
End Sub
رمز "برمجة التطبيقات" المكافئ
function test() {
 var a = 0;
 start: do {
   console.log(a);
   while (a < 100) {
     a = a + 1;
     if (a % 3 == 0) {
       continue start;
     }
   }
   break start;
 } while (true);
}

المثال 2: استبدال GoTo بـ For Loop

رمز VBA الأصلي
Sub Test()
 a = 0
 For i = 1 to 100
   For j = 1 to 10
     a =a a + 1
     If i + j > 50
       GoTo endLoop
     End If
   Next j
 Next i
 endLoop: MsgBox a
End Sub
رمز "برمجة التطبيقات" المكافئ
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);
}

واجهة برمجة تطبيقات متوافقة جزئيًا

بالنسبة إلى واجهات برمجة التطبيقات المتوافقة جزئيًا، تتوفّر بعض مَعلمات الإدخال في Apps Script، بينما لا تتوفّر بعضها الآخر.

على سبيل المثال، يتم استخدام واجهة برمجة التطبيقات legend_position في VBA لتحديد وسيلة الإيضاح في رسم بياني في Excel. تتيح هذه السمة استخدام أنواع متعددة من قيم الإدخال، بما في ذلك:

  • xlLegendPositionBottom: يضع وسيلة الإيضاح في أسفل الرسم البياني.
  • xlLegendPositionCorner: تضع وسيلة الإيضاح في زاوية الرسم البياني.
  • xlLegendPositionCustom: تضع وسيلة الإيضاح في مواضع مخصّصة على الرسم البياني.

تحتوي Apps Script على رمز مكافئ لا يتوافق إلا مع بعض هذه القيم. لا يمكن استخدام القيم التالية:

  • xlLegendPositionCorner
  • xlLegendPositionCustom

لوضع علامة على القيم غير المتوافقة لواجهات برمجة التطبيقات المتوافقة جزئيًا في الرمز المحوَّل، تتم إضافة شرط التحقّق إلى الملف 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);
}

إصلاح أخطاء واجهة برمجة التطبيقات غير المتوافقة جزئيًا

حدِّد الدالة _handle_<API_name>_error لاستبدال القيم غير المسموح بها بحلّ بديل مقبول يناسب احتياجاتك.

  1. افتح رمز Apps Script المحوَّل في مكان الخطأ. يُرجى الاطّلاع على العثور على الأخطاء.
  2. اقرأ التعليق فوق الدالة لمعرفة القيم المسموح بها وغير المسموح بها.
  3. بالنسبة إلى القيم غير المسموح بها، حدِّد القيم المسموح بها التي يمكن أن تحلّ محلّها.
  4. عدِّل الدالة _handle_<API_name>_error لعرض قيمة متوافقة بدلاً من ذلك.
  5. إذا لم تتمكّن من العثور على طريقة لاستبدال القيمة غير المتوافقة، لن تتمكّن من تحويل هذا الماكرو.

مثال على خطأ في واجهة برمجة تطبيقات غير متوافقة جزئيًا

يقدّم المثال التالي تفاصيل إضافية عن واجهة برمجة التطبيقات VBA legend_position المذكورة أعلاه. اطّلِع على واجهة برمجة التطبيقات المتوافقة جزئيًا.

في ما يلي مثال على رمز 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 إلى "برمجة تطبيقات Google"، ولكنّ ذلك يتطلّب حلاً بديلاً.

في تقرير التوافق الذي أنشأته قبل التحويل، تم تصنيف هذا النوع من واجهات برمجة التطبيقات على أنّه متوافق مع حلول بديلة.

إذا لم يتم إصلاح هذا النوع من واجهات برمجة التطبيقات في رمز VBA قبل تحويل الملف، سيظهر على النحو التالي في مشروع "برمجة تطبيقات Google":

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

حلّ الأخطاء التي تتطلّب إجراءً يدويًا

تنفيذ حل بديل لواجهة برمجة التطبيقات لجعلها تعمل على النحو المنشود 1. افتح رمز Apps Script المحوَّل في مكان الخطأ. يُرجى الاطّلاع على العثور على الأخطاء. 1. اقرأ التعليق فوق الدالة لمعرفة واجهات برمجة التطبيقات التي يمكن استخدامها كحل بديل. 1. إذا لم تتمكّن من العثور على حل بديل مناسب، ننصحك بإزالة واجهة برمجة التطبيقات من الرمز البرمجي. 1. إذا لم تتمكّن من العثور على حلّ بديل أو إزالة واجهة برمجة التطبيقات هذه من الرمز البرمجي وظهر خطأ في وحدة الماكرو، لن تتمكّن من تحويل وحدة الماكرو هذه.

أمثلة على أخطاء تتطلّب تدخّلاً يدويًا

في ما يلي أمثلة على واجهات برمجة التطبيقات التي تعرض أخطاء "مطلوب اتّخاذ إجراء يدوي" وكيفية إصلاحها:

المثال 1: Autocorrect.Addreplacement

في المثال التالي، يمكن تحويل واجهة برمجة التطبيقات VBA Autocorrect.Addreplacement، ولكنها تحتاج إلى حل بديل. يقترح &quot;محوّل الماكرو&quot; كيفية تنفيذ الدالة في تعليقات الرمز البرمجي.

/**
* 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:

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 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 في مشروع "برمجة التطبيقات":
/**
* 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 '';
}

كما هو موضّح في التعليقات الواردة في المثال أعلاه، عليك تحويل الملفات المستهدَفة إلى ملفات &quot;جداول بيانات Google&quot; على 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

بعد ذلك، عدِّل الرمز في دالة "برمجة تطبيقات Google" لفتح الملفات حسب المعرّف، كما هو موضح أدناه:

/**
* 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، سيعرض الرمز البرمجي استثناءً. في "برمجة تطبيقات Google"، يعرض الرمز البرمجي القيمة غير محدّدة.

لتجنُّب النتائج غير المتوقّعة، يضيف &quot;محوّل وحدات الماكرو&quot; رمز Apps Script الذي يعرض استثناءً إذا حاولت الوصول إلى عناصر خارج حدود مصفوفة.

يظهر هذا المثال في الرمز البرمجي أدناه:

رمز VBA الأصلي
Dim arr
arr = Array("apple", "orange")
MsgBox arr(5)
Will throw the following error:
Subscript out of range
رمز "برمجة تطبيقات Google" المحوَّل (قبل إضافة خطأ الاستثناء)
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));