افزونه 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_<API_name>(param1, param2, ....) { ThrowException("APInot supported yet." ); }
رفع خطاهای API اجرا نشده
API اجرا نشده را با APIهای Apps Script یا کتابخانه های JS موجود تعریف کنید. برای این کار مراحل زیر را دنبال کنید:
- کد Apps Script تبدیل شده را در محل خطا باز کنید. به یافتن خطاها مراجعه کنید.
- در بالای تابع، نظر اضافه شده را بخوانید. در برخی موارد، نظر نحوه پیاده سازی API را در Apps Script نشان می دهد.
- اگر نمی توانید راهی برای پیاده سازی API در Apps Script پیدا کنید، آن را از کد خود حذف کنید.
- اگر نمی توانید راه حلی پیدا کنید یا این 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 ببینید.
در این مثال، یاد خواهید گرفت:
- چگونه API
name()به یک تابع جدید در فایلvariant_resolution.gsتبدیل میشود . - نحوه فراخوانی تابع جدید در کد تبدیل شده
- نحوه ایجاد یک راه حل برای
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
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خاص را برمی گرداند.
-
_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 زیر پشتیبانی نمیشوند:
- آدرس
- اعلام کنید
- DefType
- GoSub
- رفتن به
- اجرا می کند
- Lset
- باز کنید
- RaiseEvent
- نام
- رزومه
- تنظیم مجدد
- TypeOf
- کلاس
- ماژول های کلاس
رفع خطاهای ساخت زبان اجرا نشده
- کد خود را به روز کنید تا منطق شما بر ساختار زبان پشتیبانی نشده تکیه نکند.
- کد Apps Script تبدیل شده را در محل خطا باز کنید. به یافتن خطاها مراجعه کنید.
- بر اساس منطق کد، آن را به گونه ای به روز کنید که به ساختار زبان پشتیبانی نشده نیاز نداشته باشد.
- اگر نمی توانید راهی برای بازنویسی کد خود بدون ساختار زبان پشتیبانی نشده پیدا کنید، نمی توانید این ماکرو را تبدیل کنید.
نمونه هایی از خطاهای ساخت زبان اجرا نشده
یکی از رایجترین ساختارهای زبانی اجرا نشده، عبارت 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 Subfunction 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 Subfunction 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 را تعریف کنید تا مقادیر پشتیبانی نشده را با یک راه حل قابل قبول برای نیازهای شما جایگزین کنید.
- کد Apps Script تبدیل شده را در محل خطا باز کنید. به یافتن خطاها مراجعه کنید.
- نظر بالای تابع را بخوانید تا متوجه شوید کدام مقادیر پشتیبانی می شوند و کدام ها پشتیبانی نمی شوند.
- برای مقادیر پشتیبانی نشده، تعیین کنید که کدام مقادیر پشتیبانی شده می توانند به عنوان جایگزین مناسب عمل کنند.
- تابع
_handle_<API_name>_errorبه روز کنید تا یک مقدار پشتیبانی شده را به جای آن بازگردانید. - اگر نمی توانید راهی برای جایگزینی مقدار پشتیبانی نشده پیدا کنید، نمی توانید این ماکرو را تبدیل کنید.
مثالی از یک خطای 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 convertAPI. 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("APInot supported yet." ); }
رفع خطاهای مورد نیاز کار دستی
راهحلی برای API پیادهسازی کنید تا API طبق برنامه کار کند. 1. کد Apps Script تبدیل شده را در محل خطا باز کنید. به یافتن خطاها مراجعه کنید. 1. نظر بالای تابع را بخوانید تا بفهمید کدام API میتواند برای راهحل استفاده شود. 1. اگر نمی توانید راه حل مناسبی پیدا کنید، API را از کد خود حذف کنید. 1. اگر نتوانستید راهحلی پیدا کنید یا این API را از کد خود حذف کنید و ماکرو شما خطایی ایجاد کند، نمیتوانید این ماکرو را تبدیل کنید.
نمونه هایی از کارهای دستی به خطاهای مورد نیاز
در اینجا نمونههایی از APIهایی هستند که خطاهای مورد نیاز کار دستی را ایجاد میکنند و نحوه رفع آنها:
-
Implement a workaround for Autocorrect.Addreplacement. -
Implement a workaround for workbook.open(). این مثال نحوه باز کردن فایلها در Google Drive با Apps Script را نشان میدهد.
مثال 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 rangevar 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));
مقالات مرتبط
- نمای کلی افزونه Macro Converter
- تعیین کنید که آیا ماکروهای VBA سازگار هستند یا خیر
- ماکروهای VBA را به Apps Script تبدیل کنید
- به مسائل رایج رسیدگی کنید
- آموزش مبدل ماکرو را تماشا کنید
- لیستی از APIهای VBA سازگار
افزونه 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_<API_name>(param1, param2, ....) { ThrowException("APInot supported yet." ); }
رفع خطاهای API اجرا نشده
API اجرا نشده را با APIهای Apps Script یا کتابخانه های JS موجود تعریف کنید. برای این کار مراحل زیر را دنبال کنید:
- کد Apps Script تبدیل شده را در محل خطا باز کنید. به یافتن خطاها مراجعه کنید.
- در بالای تابع، نظر اضافه شده را بخوانید. در برخی موارد، نظر نحوه پیاده سازی API را در Apps Script نشان می دهد.
- اگر نمی توانید راهی برای پیاده سازی API در Apps Script پیدا کنید، آن را از کد خود حذف کنید.
- اگر نمی توانید راه حلی پیدا کنید یا این 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 ببینید.
در این مثال، یاد خواهید گرفت:
- چگونه API
name()به یک تابع جدید در فایلvariant_resolution.gsتبدیل میشود . - نحوه فراخوانی تابع جدید در کد تبدیل شده .
- نحوه ایجاد یک راه حل برای
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
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خاص را برمی گرداند.
-
_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 زیر پشتیبانی نمیشوند:
- آدرس
- اعلام کنید
- DefType
- GoSub
- رفتن به
- اجرا می کند
- Lset
- باز کنید
- RaiseEvent
- نام
- رزومه
- تنظیم مجدد
- TypeOf
- کلاس
- ماژول های کلاس
رفع خطاهای ساخت زبان اجرا نشده
- کد خود را به روز کنید تا منطق شما بر ساختار زبان پشتیبانی نشده تکیه نکند.
- کد Apps Script تبدیل شده را در محل خطا باز کنید. به یافتن خطاها مراجعه کنید.
- بر اساس منطق کد، آن را به گونه ای به روز کنید که به ساختار زبان پشتیبانی نشده نیاز نداشته باشد.
- اگر نمی توانید راهی برای بازنویسی کد خود بدون ساختار زبان پشتیبانی نشده پیدا کنید، نمی توانید این ماکرو را تبدیل کنید.
نمونه هایی از خطاهای ساخت زبان اجرا نشده
یکی از رایجترین ساختارهای زبانی اجرا نشده، عبارت 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 Subfunction 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 Subfunction 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 را تعریف کنید تا مقادیر پشتیبانی نشده را با یک راه حل قابل قبول برای نیازهای شما جایگزین کنید.
- کد Apps Script تبدیل شده را در محل خطا باز کنید. به یافتن خطاها مراجعه کنید.
- نظر بالای تابع را بخوانید تا متوجه شوید کدام مقادیر پشتیبانی می شوند و کدام ها پشتیبانی نمی شوند.
- برای مقادیر پشتیبانی نشده، تعیین کنید که کدام مقادیر پشتیبانی شده می توانند به عنوان جایگزین مناسب عمل کنند.
- تابع
_handle_<API_name>_errorبهروزرسانی کنید تا یک مقدار پشتیبانی شده را به جای آن بازگردانید. - اگر نمی توانید راهی برای جایگزینی مقدار پشتیبانی نشده پیدا کنید، نمی توانید این ماکرو را تبدیل کنید.
مثالی از یک خطای 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 convertAPI. 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("APInot supported yet." ); }
رفع خطاهای مورد نیاز کار دستی
راهحلی برای API پیادهسازی کنید تا API طبق برنامه کار کند. 1. کد Apps Script تبدیل شده را در محل خطا باز کنید. به یافتن خطاها مراجعه کنید. 1. نظر بالای تابع را بخوانید تا بفهمید کدام API میتواند برای راهحل استفاده شود. 1. اگر نمی توانید راه حل مناسبی پیدا کنید، API را از کد خود حذف کنید. 1. اگر نتوانستید راهحلی پیدا کنید یا این API را از کد خود حذف کنید و ماکرو شما خطایی ایجاد کند، نمیتوانید این ماکرو را تبدیل کنید.
نمونه هایی از کارهای دستی به خطاهای مورد نیاز
در اینجا نمونههایی از APIهایی هستند که خطاهای مورد نیاز کار دستی را ایجاد میکنند و نحوه رفع آنها:
-
Implement a workaround for Autocorrect.Addreplacement. -
Implement a workaround for workbook.open(). این مثال نحوه باز کردن فایلها در Google Drive با Apps Script را نشان میدهد.
مثال 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 rangevar 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));
مقالات مرتبط
- نمای کلی افزونه Macro Converter
- تعیین کنید که آیا ماکروهای VBA سازگار هستند یا خیر
- ماکروهای VBA را به Apps Script تبدیل کنید
- به مسائل رایج رسیدگی کنید
- آموزش مبدل ماکرو را تماشا کنید
- List of compatible VBA APIs
The Macro Converter add-on automates most of the conversion process, but you might need to make adjustments to some APIs and other items to finalize your code.
Use this guide to understand the Apps Script files (GS files) added to your project, interpret the different error types, and learn how to fix errors.
Understand Apps Script files added to your project
Additional GS files are added to your Apps Script project to help:
- Define VBA constants and values that don't exist in Apps Script.
- Implement unconverted APIs.
- Resolve variants.
The following GS files are added to your Apps Script project:
-
Library.gs -
Unimplemented_constructs.gs -
Variant_resolutions.gs
Library.gs
In general, you don't need to modify anything in the library.gs file.
The library.gs file defines functions and constants that were used in your VBA code that don't exist in Apps Script. This helps the new Apps Script code better resemble your VBA code. Additionally, you don't need to repeat definitions every time functions or constants from the library.gs file are used.
Unimplemented_constructs.gs
The unimplemented_constructs.gs file addresses constructs or APIs that couldn't be converted by the Macro Converter. You likely need to modify this file to make your code work as intended.
Example: Window.Activate()
The following is an example of an unsupported API called Window.Activate() . The Macro Converter creates a new Apps Script function with a similar name and defines it in the unimplemented_constructs.gs file. Since the VBA function isn't supported, the new Apps Script function throws an exception.
The new function is added to the converted Apps Script code everywhere the original API was used in the VBA code.
If you find a workaround to recreate the behavior of the original API, you only need to update the definition of the function in the unimplemented_constructs.gs file. Once the function is defined there, it applies everywhere the function appears in your Apps Script project.
Here's the example in code:
Original VBA code
Window.activate()
Converted Apps Script code, added in-line
_api_window_activate();
Function definition added to the unimplemented_constructs.gs file
/** * 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
The variant_resolutions.gs file is added to your Apps Script project if an object's type can't be determined. This can happen for multiple reasons, such as an API having multiple return types or the object is declared as a variant itself.
The Macro Converter adds a new function to this file called __handle_resolve_<api>() that replaces the API in question and helps determine the object type.
In some cases, you might need to update the __handle_resolve_<api>() function to manually declare the object type. See Unsupported object type .
Example: name()
Many object types in VBA define a name() API. Usually, the Apps Script equivalent is getName() , but not for every object type. Multiple alternative cases can occur:
- The object's equivalent API is called something different than
getName(). - The object doesn't have an Apps Script API to get its name.
- There's not an equivalent Apps Script object.
When the object type isn't determined, the Macro Converter creates a new function called __handle_resolve_name in the variant_resolutions.gs file.
Here's the example in code:
Original VBA code
a = Selection.name
In this case, the API name() is called on the current selection. The selection could be a Sheet object or a Shape object. If it's a Sheet object, the translation is getName() , but if it's a Shape object, there is no equivalent in Apps Script.
Converted Apps Script code, added in-line
a = __handle_resolve_name({}, getActiveSelection(), {});The __handle_resolve_name() function below is added to the variant_resolution.gs file to solve for different object types. The function checks the object type, then uses getName() if it's supported, or throws an error if getName() isn't supported.
Function definition added to the variant_resolution.gs file
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; }
Find errors
When you run into an error in the converted Apps Script code, the message specifies the type of error and its location. The format of the error message depends on which Apps Script runtime you're using.
If you're in the default V8 runtime, you'll see an error that looks like the following:
_api_windows_active (unimplemented_constructs:2:3)
This means the error is located in the unimplemented_constructs.gs file at line 2, character 3.
If you're in the deprecated Rhino runtime, you'll see an error that looks like the following:
unimplemented_constructs:2 (_api_windows_active)
This means the error is located in the unimplemented_constructs.gs file at line 2.
انواع خطا
You can fix most of the errors you run into in the unimplemented_constructs.gs and variant_resolution.gs files described above.
The types of errors you might run into include:
- Unimplemented API
- Unimplemented language construct
- Partially supported API
- Manual work needed
- Intentional Error
Unimplemented API
An unimplemented API is an API that the Macro Converter can't convert from VBA to Apps Script and there isn't a known workaround for the API.
Unimplemented APIs are usually added as empty functions—sometimes with empty signatures—to the unimplemented_constructs.gs file. If the object type couldn't be determined, the unimplemented API might be added to the variant_resolution.gs file, instead.
In the compatibility report you generated before the conversion, this API is labeled as Needs more investigation .
If you don't fix this type of API in your VBA code before you convert your file, here's how it appears in the Apps Script project:
/** * 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("APInot supported yet." ); }
Fix unimplemented API errors
Define the unimplemented API with existing Apps Script APIs or JS libraries. برای این کار مراحل زیر را دنبال کنید:
- Open the converted Apps Script code at the location of the error. See Find errors .
- Above the function, read the comment that was added. In some cases, the comment suggests how to implement the API in Apps Script.
- If you can't find a way to implement the API in Apps Script, consider removing it from your code.
- If you can't find a workaround or remove this API from your code and your macro throws this error, you can't convert this macro.
Examples of unimplemented API errors
Here are examples of unimplemented API scenarios and how to fix them:
- There's no equivalent Apps Script : Shows an indirect workaround for
Chart.Protect, an API that doesn't exist in Apps Script. - An unknown object type : Shows how to handle an object type that's a variable, and how to implement an unsupported object type that can be recreated in Apps Script.
Example 1: No equivalent Apps Script or unknown API
In this example, Chart.Protect wasn't automatically converted because there isn't a way to protect a chart in 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(); } }
Example 2: Unsupported object type
When the object type is unknown, the unimplemented API error is added to the variant_resolution.gs file. The following example expands on the VBA name() API example above. See variant_resolution.gs .
In this example, you'll learn:
- How the
name()API is converted to a new function in thevariant_resolution.gsfile . - How the new function is called in the converted code .
- How to create a workaround for
CommandBar, an unsupported object type, in Apps Script .
1. Since the converted code can't determine the exact object type that name() is called on, the Macro Converter creates a new function called __handle_resolve_name , shown below.
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. Suppose the VBA code defines a PrintName() function that calls the name() API. The VBA code is shown below:
‘Defining a function that prints the name of the object in parameter Sub PrintName(obj as Variant) Debug.Print obj.Name End Sub
function PrintName(obj) {
Logger.log(_handle_resolve_name(obj));
} 3. Suppose your VBA code calls the PrintName() function on the object type CommandBar . The VBA code is shown below:
PrintName Application.CommandBars.item("Standard")CommandBar isn't supported in Apps Script and as a result, the two methods used in the VBA code above are also not supported.-
Application.CommandBars(): In VBA, this returns a list of allCommandBarobjects. -
CommandBars.item(): In VBA, this returns a specificCommandBarobject.
-
_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.'); }
To get the new functions to work, take the following steps:
3.1 Define a new object type that creates the functionalities of CommandBars and a new collection of CommandBars similar to what exists in VBA.
3.2 Add a getName() method for the new object type.
Steps 3.1 and 3.2 are shown in the code below. Menu objects are created as a new object type that mimics the behavior of 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 Modify the __handle_resolve_name function in the variant_resolution.gs file to handle the new object type. Add a section to the function, as shown below:
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 Define the two functions created in the unimplemented_constructs.gs file ( _api_application_commandbars() , _api_commandbars_item() ). This step makes sure the original calls of the function work.
//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); }
Unimplemented language constructs
A construct is an element of the code language that controls execution flow or data display. For example, loops, labels, events, and gotos. Here's a list of all VBA constructs .
Constructs that the Macro Converter can't convert are considered unimplemented language constructs .
Where the Macro Converter determines that an unimplemented language construct exists, it inserts a TODO comment.
The following VBA constructs aren't supported:
- AddressOf
- اعلام کنید
- DefType
- GoSub
- رفتن به
- اجرا می کند
- Lset
- باز کنید
- RaiseEvent
- نام
- رزومه
- Rset
- TypeOf
- کلاس
- ماژول های کلاس
Fix unimplemented language construct errors
- Update your code so that your logic doesn't rely on the unsupported language construct.
- Open the converted Apps Script code at the location of the error. See Find errors .
- Based on the logic of the code, update it in a way that doesn't require the unsupported language construct.
- If you can't find a way to rewrite your code without the unsupported language construct, you can't convert this macro.
Examples of unimplemented language construct errors
One of the most common unimplemented language constructs is a GoTo statement. You can replace some VBA GoTo statements with loops. Below are two examples of using loops instead of GoTo statements.
Example 1: Replace GoTo with While Loop
Original VBA code 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 Subfunction 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); }
Example 2: Replace GoTo with For Loop
Original VBA codeSub 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 Subfunction 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); }
Partially supported API
For Partially supported APIs , some input parameters are supported in Apps Script and some aren't.
For example, the VBA API legend_position is used to define the legend in an Excel graph. It supports multiple types of input values, including:
-
xlLegendPositionBottom: Puts the legend at the bottom of the chart. -
xlLegendPositionCorner: Puts the legend at the corner of the chart. -
xlLegendPositionCustom: Puts the legend at custom positions on the chart.
Apps Script has an equivalent code that supports only some of those values. The following values are not supported:
-
xlLegendPositionCorner -
xlLegendPositionCustom
To flag unsupported values of partially supported APIs in your converted code, a validating condition is added to the library.gs file that checks for those values. به عنوان مثال:
if (position == xlLegendPositionCorner ||
position == xlLegendPositionCustom) {
position = _handle_legend_position_error(position);
} If the validating condition finds one of the unsupported values, an error handler function, _handle_<API_name>_error , is created in the unimplemented_constructs.gs file.
The function throws a user error and won't replace the value with a supported value. به عنوان مثال:
/** * 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); }
Fix partially supported API errors
Define the _handle_<API_name>_error function to replace the unsupported values with an acceptable workaround for your needs.
- Open the converted Apps Script code at the location of the error. See Find errors .
- Read the comment above the function to understand which values are supported and which aren't.
- For the unsupported values, determine which supported values can act as a suitable replacement.
- Update the function
_handle_<API_name>_errorto return a supported value instead. - If you can't find a way to replace the unsupported value, you can't convert this macro.
Example of a partially supported API error
The following example expands on the VBA API legend_position mentioned above. See Partially supported API .
Below is an example of original VBA code that uses an unsupported value, xlLegendPositionCustom .
Charts(1).Legend.Position = xlLegendPositionCustom
The Macro Converter adds the below function to the unimplemented_constructs.gs file:
/** * 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); }
Manual work needed
Manual work needed means that the VBA API can be converted into Apps Script, but it needs a workaround.
In the compatibility report you generated before the conversion, this type of API is labeled as Supported with workarounds .
If you don't fix this type of API in your VBA code before you convert your file, here's how it appears in the Apps Script project:
/** * Could not convertAPI. 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("APInot supported yet." ); }
Fix manual work needed errors
Implement a workaround for the API to get the API to work as intended. 1. Open the converted Apps Script code at the location of the error. See Find errors . 1. Read the comment above the function to understand which APIs can be used for a workaround. 1. If you can't find a suitable workaround, consider removing the API from your code. 1. If you can't find a workaround or remove this API from your code and your macro throws an error, you can't convert this macro.
Examples of Manual work needed errors
Here are examples of APIs that throw Manual work needed errors and how to fix them:
-
Implement a workaround for Autocorrect.Addreplacement. -
Implement a workaround for workbook.open(). This example shows how to open files in Google Drive with Apps Script.
Example 1: Autocorrect.Addreplacement
In the following example, the VBA API Autocorrect.Addreplacement can be converted, but it needs a workaround. The Macro Converter suggests how to implement the function in the code comments.
/** * 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.'); }
The implementation of the Autocorrect.Addreplacement API is shown below:
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)); }
Example 2: Workbook.open()
The VBA API workbook.open() opens a local file based on a file path.
Suppose there are two files being opened by workbook.open() in the VBA code:
- File 1:
C:\Data\abc.xlsx - File 2:
C:\Data\xyz.xlsx
The below shows how the Macro Converter replaces Workbook.open() with Apps Script everywhere Workbook.open() is used to open File 1:
var spreadSheetId = _handle_mso_excel_get_google_spreadsheet_id("C:\Data\abc.xlsx"); var spreadSheet = SpreadsheetApp.openById(spreadSheetId);
unimplemented_constructs.gs file in the Apps Script project: /** * 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 '' ; }
As instructed by the comments in the sample above, you need to convert the target files to Google Sheets files on Google Drive.
The corresponding Google Spreadsheet IDs are bolded below:
- File #1:
C:\Data\abc.xlsxbecomeshttps://docs.google.com/spreadsheets/d/ abc123Abc123Abc123abc - File #2:
C:\Data\abc.xlsxbecomeshttps://docs.google.com/spreadsheets/d/ xyz456Xyz456xYz456xyZ
Then, modify the code in the Apps Script function to open the files by ID, as shown below:
/** * 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"; }
Intentional error
Intentional errors are added to your converted code to mimic the error behavior of your original VBA code. You don't need to modify these errors.
Example of an intentional error
If you try to access an element beyond the bounds of an array in VBA, the code throws an exception. In Apps Script, the code returns undefined.
To avoid unexpected results, the Macro Converter adds Apps Script code that throws an exception if you try to access elements beyond the bounds of an array.
This example is shown in the code below:
Original VBA codeDim arr
arr = Array("apple", "orange")
MsgBox arr(5)
Will throw the following error:
Subscript out of rangevar 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));
مقالات مرتبط
- Macro Converter add-on overview
- Determine if VBA macros are compatible
- ماکروهای VBA را به Apps Script تبدیل کنید
- به مسائل رایج رسیدگی کنید
- Watch Macro Converter tutorials
- List of compatible VBA APIs