Naprawianie błędów w przekonwertowanym kodzie

Dodatek Konwerter makr automatyzuje większość procesu konwersji, ale do ostatecznego skompilowania kodu może być konieczne dostosowanie niektórych interfejsów API i innych elementów.

Z tego przewodnika dowiesz się, jak interpretować pliki Apps Script (pliki GS) dodane do projektu, jak interpretować różne typy błędów i jak je naprawiać.

Informacje o plikach Apps Script dodanych do projektu

Do projektu Apps Script są dodawane dodatkowe pliki GS, aby:

  • Definiowanie stałych i wartości VBA, które nie występują w Apps Script.
  • Wdrażanie nieprzekształconych interfejsów API.
  • Rozwiąż warianty.

Do projektu Apps Script są dodawane te pliki GS:

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

Library.gs

Zazwyczaj nie musisz niczego zmieniać w pliku library.gs.

Plik library.gs definiuje funkcje i stałe, które były używane w kodzie VBA, a których nie ma w Apps Script. Dzięki temu nowy kod Apps Script będzie bardziej przypominać kod VBA. Dodatkowo nie musisz powtarzać definicji za każdym razem, gdy używasz funkcji lub stałych z pliku library.gs.

Unimplemented_constructs.gs

Plik unimplemented_constructs.gs zawiera elementy lub interfejsy API, których nie można przekonwertować za pomocą dodatku Macro Converter. Prawdopodobnie musisz zmodyfikować ten plik, aby kod działał zgodnie z oczekiwaniami.

Przykład: Window.Activate()

Oto przykład nieobsługiwanego interfejsu API o nazwie Window.Activate(). Konwerter makr tworzy nową funkcję Apps Script o podobnej nazwie i definiuje ją w pliku unimplemented_constructs.gs. Ponieważ funkcja VBA nie jest obsługiwana, nowa funkcja Apps Script powoduje wyjątek.

Nowa funkcja jest dodawana do przekonwertowanego kodu Apps Script wszędzie tam, gdzie w kodzie VBA używano oryginalnego interfejsu API.

Jeśli znajdziesz obejście, które pozwoli odtworzyć działanie oryginalnego interfejsu API, wystarczy zaktualizować definicję funkcji w pliku unimplemented_constructs.gs. Gdy funkcja zostanie zdefiniowana, będzie obowiązywać wszędzie tam, gdzie pojawia się w Twoim projekcie Apps Script.

Oto przykładowy kod:

Oryginalny kod VBA

Window.activate()

Konwertowany kod Apps Script dodany w postaci inline

_api_window_activate();

Definicja funkcji została dodana do pliku 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

Plik variant_resolutions.gs jest dodawany do projektu Apps Script, jeśli nie można określić typu obiektu. Może się tak zdarzyć z różnych powodów, np. gdy interfejs API ma kilka typów zwracanych wartości lub gdy obiekt jest zadeklarowany jako wariant.

Konwerter makr dodaje do tego pliku nową funkcję o nazwie __handle_resolve_<api>(), która zastępuje interfejs API i pomaga określić typ obiektu.

W niektórych przypadkach konieczne może być zaktualizowanie funkcji __handle_resolve_<api>(), aby ręcznie zadeklarować typ obiektu. Zobacz Nieobsługiwany typ obiektu.

Przykład: name()

Wiele typów obiektów w VBA definiuje interfejs API name(). Zwykle odpowiednikiem w Google Apps Script jest getName(), ale nie w przypadku każdego typu obiektu. Może wystąpić kilka alternatywnych przypadków:

  • Odpowiednik interfejsu API obiektu ma inną nazwę niż getName().
  • Obiekt nie ma interfejsu Apps Script API, który umożliwia uzyskanie jego nazwy.
  • Brak odpowiedniego obiektu Apps Script.

Gdy typ obiektu nie jest określony, Konwerter makr tworzy w pliku variant_resolutions.gs nową funkcję o nazwie __handle_resolve_name.

Oto przykładowy kod:

Oryginalny kod VBA

a = Selection.name

W tym przypadku wywoływany jest interfejs API name() w przypadku bieżącego zaznaczenia. Zaznaczony element może być obiektem Arkusz lub obiektem Kształt. Jeśli jest to obiekt Arkusz, odpowiednikiem jest getName(), ale jeśli jest to obiekt kształtu, nie ma odpowiednika w Apps Script.

Konwertowany kod Apps Script, dodany w wersji inline

a = __handle_resolve_name({}, getActiveSelection(), {});

Funkcja __handle_resolve_name() poniżej jest dodawana do pliku variant_resolution.gs, aby rozwiązać problemy dotyczące różnych typów obiektów. Funkcja sprawdza typ obiektu, a następnie używa funkcji getName(), jeśli jest ona obsługiwana, lub zgłasza błąd, jeśli nie jest obsługiwana.getName()

Definicja funkcji została dodana do pliku 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;
}

Znajdowanie błędów

Gdy w przekształconym kodzie Apps Script wystąpi błąd, komunikat określa jego typ i lokalizację. Format komunikatu o błędzie zależy od używanego środowiska wykonawczego Apps Script.

Jeśli używasz domyślnego środowiska wykonawczego V8, zobaczysz błąd podobny do tego:

_api_windows_active (unimplemented_constructs:2:3)

Oznacza to, że błąd znajduje się w pliku unimplemented_constructs.gs w wierszu 2, znak 3.

Jeśli używasz przestarzałego środowiska Rhino, zobaczysz błąd podobny do tego:

unimplemented_constructs:2 (_api_windows_active)

Oznacza to, że błąd znajduje się w pliku unimplemented_constructs.gs w wierszu 2.

Typy błędów

Większość błędów, na które możesz się natknąć, możesz naprawić w opisanych powyżej plikach unimplemented_constructs.gsvariant_resolution.gs.

Oto typy błędów, które mogą wystąpić:

Niewdrożone interfejsy API

Niewdrożony interfejs API to interfejs API, którego nie można przekonwertować z VBA na Apps Script za pomocą dodatku Macro Converter. Nie jest znane żadne obejście tego problemu.

Niewdrożone interfejsy API są zwykle dodawane jako puste funkcje (czasami z pustymi sygnaturami) do pliku unimplemented_constructs.gs. Jeśli nie można określić typu obiektu, do pliku variant_resolution.gs może zostać dodany niewdrożony interfejs API.

W raporcie zgodności wygenerowanym przed konwersją to API jest oznaczone jako wymagające dalszej analizy.

Jeśli przed konwersją pliku nie naprawisz tego typu interfejsu API w kodzie VBA, tak będzie on wyglądał w projekcie Apps Script:

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

Naprawianie błędów w niewdrożonym interfejsie API

Określ niewdrożone interfejsy API za pomocą istniejących interfejsów Apps Script API lub bibliotek JS. W tym celu wykonaj następujące czynności:

  1. Otwórz przekonwertowany kod Apps Script w miejscu, w którym wystąpił błąd. Zobacz Znajdowanie błędów.
  2. Nad funkcją przeczytaj dodany komentarz. W niektórych przypadkach komentarz zawiera sugestie dotyczące implementacji interfejsu API w Apps Script.
  3. Jeśli nie możesz znaleźć sposobu na implementację interfejsu API w Google Apps Script, rozważ usunięcie go z kodu.
  4. Jeśli nie możesz znaleźć obejścia problemu ani usunąć tego interfejsu API z kodu, a makro zgłasza ten błąd, nie możesz przekonwertować tego makra.

Przykłady niewdrożonych błędów interfejsu API

Oto przykłady niewdrożonych scenariuszy interfejsu API i sposobów ich naprawy:

  • Nie ma odpowiednika w Apps Script: pokazuje obejście problemu dotyczące Chart.Protect, interfejsu API, którego nie ma w Apps Script.
  • Nieznany typ obiektu: pokazuje, jak obsługiwać typ obiektu, który jest zmienną, oraz jak zaimplementować nieobsługiwany typ obiektu, który można odtworzyć w Apps Script.
Przykład 1. Brak odpowiednika w Apps Script lub nieznany interfejs API

W tym przykładzie Chart.Protect nie został automatycznie przekonwertowany, ponieważ nie można chronić wykresu w Arkuszach 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.');
}
Chociaż nie możesz chronić wykresu, możesz chronić zakres danych na wykresie, aby nie można było zmienić tych danych.

Poniżej przedstawiamy przykładową implementację ochrony zakresu:
/**
* 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();
}
}
Przykład 2. Nieobsługiwany typ obiektu

Jeśli typ obiektu jest nieznany, do pliku variant_resolution.gs jest dodawany błąd niewdrożonego interfejsu API. Ten przykład rozwija powyższy przykład interfejsu API VBA name(). Zobacz variant_resolution.gs.

Z tego przykładu dowiesz się:

  1. Jak interfejs API name() jest przekształcany w nową funkcję w pliku variant_resolution.gs.
  2. Jak nowa funkcja jest wywoływana w przekształconym kodzie.
  3. Jak obejść problem z obsługiwanym typem obiektu CommandBar w Apps Script

1. Konwerter makr nie może określić dokładnego typu obiektu, do którego jest wywoływane makro name(). Dlatego tworzy nową funkcję o nazwie __handle_resolve_name, jak pokazano poniżej.

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. Załóżmy, że kod VBA definiuje funkcję PrintName(), która wywołuje interfejs API name(). Poniżej znajduje się kod VBA:

‘Defining a function that prints the name of the object in parameter
Sub PrintName(obj as Variant)
  Debug.Print obj.Name
End Sub
Ponieważ funkcja name() jest wywoływana na obiekcie, który jest zmienną, przekonwertowany kod nie zna typu obiektu w momencie konwersji. Przekształcony kod Apps Script wywoła funkcję `__handle_resolve_name`:
function PrintName(obj) {
  Logger.log(_handle_resolve_name(obj));
}

3. Załóżmy, że kod VBA wywołuje funkcję PrintName() dla obiektu typu CommandBar. Poniżej znajduje się kod VBA:

PrintName Application.CommandBars.item("Standard")
Funkcja CommandBar nie jest obsługiwana w Apps Script, dlatego też 2 metody użyte w powyższym kodzie VBA również nie są obsługiwane.
  • Application.CommandBars(): w VBA zwraca listę wszystkich obiektów CommandBar.
  • CommandBars.item(): w VBA zwraca określony obiekt CommandBar.
Ponieważ ten typ obiektu nie jest obsługiwany w Apps Script, przekonwertowany kod tworzy w pliku „unimplemented_constructs.gs” następujące funkcje, które musisz zdefiniować.
  • _api_application_commandbars()
  • _api_commandbars_item()
Funkcje są wywoływane w przetworzonym kodzie w ten sposób:
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.');
}

Aby nowe funkcje działały, wykonaj te czynności:

3.1 Zdefiniuj nowy typ obiektu, który tworzy funkcje CommandBarsoraz nową kolekcję CommandBars podobną do tej, która występuje w VBA.

3.2. Dodaj metodę getName() dla nowego typu obiektu.

Kroki 3.1 i 3.2 są pokazane w poniżej zamieszczonym kodzie. Obiekty menu są tworzone jako nowy typ obiektu, który naśladuje działanie obiektu 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 W pliku variant_resolution.gs zmodyfikuj funkcję __handle_resolve_name, aby obsługiwała nowy typ obiektu. Dodaj do funkcji sekcję, jak pokazano poniżej:

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 Zdefiniuj 2 funkcje utworzone w pliku unimplemented_constructs.gs (_api_application_commandbars(), _api_commandbars_item()). Dzięki temu oryginalne wywołania funkcji będą działać.

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

Niewdrożone konstrukcje językowe

Konstrukcja to element języka kodu, który kontroluje przepływ wykonywania lub wyświetlanie danych. Na przykład pętle, etykiety, zdarzenia i gotos. Oto lista wszystkich konstrukcji VBA.

Konstrukcje, których nie można przekonwertować za pomocą Konwertera makr, są uznawane za niewdrożone konstrukcje językowe.

Jeśli Konwerter makr wykryje niewdrożoną konstrukcję językową, wstawia komentarz TODO.

Te konstrukcje VBA nie są obsługiwane:

Naprawianie błędów niewdrożonych konstrukcji językowych

  1. Zaktualizuj kod, tak aby logika nie opierała się na nieobsługiwanej konstrukcji językowej.
  2. Otwórz przekonwertowany kod Apps Script w miejscu, w którym wystąpił błąd. Zobacz Znajdowanie błędów.
  3. Zmodyfikuj kod w sposób, który nie wymaga użycia nieobsługiwanego konstruktu językowego.
  4. Jeśli nie możesz znaleźć sposobu na przepisanie kodu bez nieobsługiwanego elementu języka, nie możesz przekonwertować tego makra.

Przykłady błędów związanych z niewdrożonymi konstrukcjami językowymi

Jednym z najczęstszych niewdrożonych konstruktów językowych jest instrukcja GoTo. Niektóre instrukcje VBA GoTo możesz zastąpić pętlami. Poniżej znajdziesz 2 przykłady pętli zamiast instrukcji GoTo.

Przykład 1. Zamień GoTo na While Loop

Oryginalny kod 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
Odpowiednik kodu Apps Script
function test() {
 var a = 0;
 start: do {
   console.log(a);
   while (a < 100) {
     a = a + 1;
     if (a % 3 == 0) {
       continue start;
     }
   }
   break start;
 } while (true);
}

Przykład 2. Zastąpienie instrukcji GoTo pętlą For

Oryginalny kod 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
Odpowiednik kodu Apps Script
function test() {
 var a = 0;
 endLoop: for (var i = 1; i <= 100; i++) {
    for  (var j = 0; j <=10; j++) {
      If (i + j > 50) {
        break endLoop;
      }
    }
 }
 Browser.msgBox(a);
}

   break start;
 } while (true);
}

Częściowo obsługiwany interfejs API

W przypadku częściowo obsługiwanych interfejsów API niektóre parametry wejściowe są obsługiwane w AppsScript, a inne nie.

Na przykład interfejs VBA API legend_position służy do definiowania legendy na wykresie Excela. Obsługuje ona wiele typów wartości wejściowych, m.in.:

  • xlLegendPositionBottom: umieszcza legendę u dołu wykresu.
  • xlLegendPositionCorner: umieszcza legendę w rogu wykresu.
  • xlLegendPositionCustom: umieszcza legendę w niestandardowych miejscach na wykresie.

Apps Script ma odpowiedni kod, który obsługuje tylko niektóre z tych wartości. Te wartości nie są obsługiwane:

  • xlLegendPositionCorner
  • xlLegendPositionCustom

Aby oznaczyć nieobsługiwane wartości interfejsów API obsługiwanych częściowo w przetworzonym kodzie, do pliku library.gs dodawany jest warunek weryfikujący, który sprawdza te wartości. Na przykład:

if (position == xlLegendPositionCorner ||
     position == xlLegendPositionCustom) {
   position = _handle_legend_position_error(position);
}

Jeśli warunek weryfikujący znajdzie jedną z nieobsługiwanych wartości, w pliku unimplemented_constructs.gs zostanie utworzona funkcja obsługi błędów _handle_<API_name>_error.

Funkcja zgłasza błąd użytkownika i nie zastępuje wartości obsługiwaną wartością. Na przykład:

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

Naprawianie błędów w częściowo obsługiwanych interfejsach API

Zdefiniuj funkcję _handle_<API_name>_error, aby zastąpić wartości nieobsługiwane odpowiednim obejściem.

  1. Otwórz przekonwertowany kod Apps Script w miejscu, w którym wystąpił błąd. Zobacz Znajdowanie błędów.
  2. Aby dowiedzieć się, które wartości są obsługiwane, a które nie, przeczytaj komentarz nad funkcją.
  3. W przypadku wartości nieobsługiwanych określ, które wartości obsługiwane mogą być odpowiednią zamianą.
  4. Zaktualizuj funkcję _handle_<API_name>_error, aby zwracała obsługiwaną wartość.
  5. Jeśli nie możesz znaleźć sposobu na zastąpienie wartości nieobsługiwanej, nie możesz przekonwertować tego makra.

Przykład błędu interfejsu API, który jest częściowo obsługiwany

Ten przykład pokazuje interfejs VBA API legend_position. Zobacz Interfejsy API obsługiwane częściowo.

Poniżej znajdziesz przykład oryginalnego kodu VBA, który używa nieobsługiwanej wartości xlLegendPositionCustom.

Charts(1).Legend.Position = xlLegendPositionCustom

Konwerter makr dodaje do pliku unimplemented_constructs.gs tę funkcję:

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

Wymagane działania ręczne

Wymagane działania ręczne oznacza, że interfejs VBA API można przekonwertować na Apps Script, ale trzeba użyć obejścia.

W raporcie zgodności wygenerowanym przed konwersją ten typ interfejsu API jest oznaczony jako Obsługiwany z użyciem obejść.

Jeśli przed konwersją pliku nie naprawisz tego typu interfejsu API w kodzie VBA, tak będzie on wyglądał w projekcie Apps Script:

/**
* Could not convert  API. Please add relevant code in the following
* function to implement it.
* This API has been used at the following locations in the VBA script.
*      : 
*
* You can use the following Apps Script APIs to convert it.
* Apps Script APIs : 
* Apps Script documentation links : 
*
* @param param1 {}
* @param param2 {}
* ...
* @return {}
*/
function _api_<API_name>(param1, param2, ....) {
 ThrowException("API  not supported yet.");
}

Naprawianie błędów wymagających ręcznej interwencji

Wdrożyć obejście, aby interfejs API działał zgodnie z oczekiwaniami. 1. Otwórz przekonwertowany kod Apps Script w miejscu, w którym wystąpił błąd. Zobacz Znajdowanie błędów. 1. Przeczytaj komentarz nad funkcją, aby dowiedzieć się, których interfejsów API możesz użyć jako obejścia. 1. Jeśli nie możesz znaleźć odpowiedniego obejścia problemu, rozważ usunięcie interfejsu API z kodu. 1. Jeśli nie możesz znaleźć obejścia problemu ani usunąć tego interfejsu API z kodu, a makro zgłasza błąd, nie możesz przekonwertować tego makra.

Przykłady błędów wymagających ręcznej weryfikacji

Oto przykłady interfejsów API, które zwracają błędy wymagające ręcznej interwencji, oraz sposoby ich naprawiania:

Przykład 1. Autocorrect.Addreplacement

W tym przykładzie interfejs VBA API Autocorrect.Addreplacement można przekonwertować, ale wymaga to obejścia. Konwerter makr sugeruje, jak zaimplementować funkcję w komentarzach do kodu.

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

}

Poniżej przedstawiono implementację interfejsu 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));
}

Przykład 2: Workbook.open()

Interfejs API VBA workbook.open() otwiera plik lokalny na podstawie ścieżki do niego.

Załóżmy, że w kodzie VBA funkcja workbook.open() otwiera 2 pliki:

  • Plik 1: C:\Data\abc.xlsx
  • Plik 2: C:\Data\xyz.xlsx

Poniżej widać, jak dodatek Macro Converter zastępuje Workbook.open() kodem Apps Script wszędzie tam, gdzie Workbook.open() jest używany do otwierania pliku 1:

var spreadSheetId =
   _handle_mso_excel_get_google_spreadsheet_id("C:\Data\abc.xlsx");
var spreadSheet = SpreadsheetApp.openById(spreadSheetId);
W pliku unimplemented_constructs.gs w projekcie Apps Script pojawia się ten błąd:
/**
* 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 '';
}

Zgodnie z instrukcjami podanymi w komentarzach w powyższym przykładzie musisz przekonwertować pliki docelowe na pliki Arkuszy Google na Dysku Google.

Odpowiednie identyfikatory arkuszy kalkulacyjnych Google są wyróżnione pogrubioną czcionką:

  • Plik 1: C:\Data\abc.xlsx staje się https://docs.google.com/spreadsheets/d/abc123Abc123Abc123abc
  • Plik 2: C:\Data\abc.xlsx zmienia się na https://docs.google.com/spreadsheets/d/xyz456Xyz456xYz456xyZ

Następnie zmodyfikuj kod w funkcji Apps Script, aby otwierać pliki według identyfikatora, jak pokazano poniżej:

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

Celowy błąd

Celowe błędy są dodawane do przekonwertowanego kodu, aby odwzorować zachowanie błędu w początkowym kodzie VBA. Nie musisz modyfikować tych błędów.

Przykład celowego błędu

Jeśli spróbujesz uzyskać dostęp do elementu poza granicami tablicy w VBA, kod rzuci wyjątek. W Apps Script kod zwraca wartość undefined.

Aby uniknąć nieoczekiwanych wyników, Konwerter makr dodaje kod Apps Script, który rzuca wyjątek, jeśli spróbujesz uzyskać dostęp do elementów poza granicami tablicy.

Przykładowy kod:

Oryginalny kod VBA
Dim arr
arr = Array("apple", "orange")
MsgBox arr(5)
Will throw the following error:
Subscript out of range
Skonwertowany kod Apps Script (przed dodaniem błędu wyjątku)
var arr;
arr = ["apple", "orange"];
Browser.msgBox(arr[5]);
Will return this value and not throw an error:
undefined
Dodany kod Apps Script, który powoduje wyjątek błędu
/**
* 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));