Naprawianie błędów w przekonwertowanym kodzie

Dodatek Macro Converter automatyzuje większość procesu konwersji, ale aby dokończyć proces, konieczne może być dostosowanie niektórych interfejsów API i innych elementów.

W tym przewodniku znajdziesz informacje o plikach Apps Script (plikach GS) dodanych do projektu, interpretowanie różnych typów błędów i sposoby ich rozwiązywania.

Informacje o plikach Apps Script dodanych do projektu

Do projektu Apps Script dodawane są dodatkowe pliki GS, które ułatwiają:

  • Zdefiniuj stałe i wartości VBA, których nie ma w Apps Script.
  • Zaimplementuj interfejsy API, które nie zostały przekonwertowane.
  • Rozwiąż problemy z wariantami.

Do projektu Apps Script zostaną dodane 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 użyte w kodzie VBA, których nie ma w Apps Script. Dzięki temu nowy kod Apps Script może bardziej przypominać kod VBA. Poza tym nie musisz powtarzać definicji za każdym razem, gdy używane są funkcje lub stałe z pliku library.gs.

Unimplemented_constructs.gs

Plik unimplemented_constructs.gs zawiera adresy konstrukcji lub interfejsów API, których nie udało się przekonwertować przez konwerter makr. Prawdopodobnie trzeba będzie zmodyfikować ten plik, aby kod działał poprawnie.

Przykład: Window.Activate()

Poniżej znajdziesz 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 zgłasza wyjątek.

Nowa funkcja jest dodawana do przekonwertowanego kodu Apps Script wszędzie tam, gdzie w kodzie VBA był używany oryginalny interfejs API.

Jeśli znajdziesz obejście, które pozwoli odtworzyć działanie oryginalnego interfejsu API, musisz tylko zaktualizować definicję funkcji w pliku unimplemented_constructs.gs. Po zdefiniowaniu funkcji będzie ona stosowana wszędzie tam, gdzie występuje ona w projekcie Apps Script.

Oto przykład w kodzie:

Oryginalny kod VBA

Window.activate()

Skonwertowany kod Apps Script, dodany w tekście

_api_window_activate();

Dodano definicję funkcji 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

Jeśli nie można określić typu obiektu, do projektu Apps Script dodawany jest plik variant_resolutions.gs. Może się tak zdarzyć z wielu powodów, np. gdy interfejs API ma wiele typów zwracanych lub obiekt jest zadeklarowany jako sam wariant.

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

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

Przykład: name()

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

  • Odpowiednik API obiektu nazywa się inaczej niż getName().
  • Obiekt nie ma interfejsu Apps Script API, który pozwoliłby uzyskać jego nazwę.
  • Nie ma odpowiednika obiektu Apps Script.

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

Oto przykład w kodzie:

Oryginalny kod VBA

a = Selection.name

W tym przypadku interfejs API name() jest wywoływany w przypadku bieżącego wyboru. Możesz wybrać obiekt arkusza lub obiekt kształtu. Jeśli to obiekt arkusza, tłumaczenie to getName(), a jeśli jest to obiekt kształtu, nie ma odpowiednika w języku Apps Script.

Skonwertowany kod Apps Script, dodany w tekście

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

Poniższa funkcja __handle_resolve_name() jest dodawana do pliku variant_resolution.gs, aby rozwiązać problemy z różnymi typami obiektów. Funkcja sprawdza typ obiektu, a potem używa elementu getName(), jeśli jest obsługiwany, lub zwraca błąd, jeśli właściwość getName() nie jest obsługiwana.

Dodano definicję funkcji 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;
}

Znajdź błędy

Jeśli w przekonwertowanym kodzie Apps Script wystąpi błąd, wiadomość określa typ błędu i jego 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 taki błąd:

_api_windows_active (unimplemented_constructs:2:3)

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

Jeśli używasz wycofanego środowiska wykonawczego 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

Możesz naprawić większość błędów, które występują w plikach unimplemented_constructs.gs i variant_resolution.gs, które opisaliśmy powyżej.

Typy błędów, które możesz napotkać:

Niezaimplementowany interfejs API

Niezaimplementowany interfejs API to interfejs API, którego narzędzie Macro Converter nie może przekonwertować z VBA na Apps Script. Nie ma znanego obejścia tego problemu.

Niezaimplementowane interfejsy API są zwykle dodawane do pliku unimplemented_constructs.gs jako puste funkcje – czasem z pustymi podpisami. Jeśli nie można określić typu obiektu, do pliku variant_resolution.gs może zostać dodany niezaimplementowany interfejs API.

W raporcie zgodności wygenerowanym przed konwersją ten interfejs API jest oznaczony jako Wymaga dokładniejszej analizy.

Jeśli przed przekonwertowaniem pliku nie poprawisz tego typu interfejsu API w kodzie VBA, w projekcie Apps Script będzie to wyglądało tak:

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

Naprawianie błędów w interfejsie API

Zdefiniuj niezaimplementowany interfejs API za pomocą istniejących interfejsów API Apps Script 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 sugeruje, jak wdrożyć interfejs API w Apps Script.
  3. Jeśli nie możesz znaleźć sposobu na zaimplementowanie interfejsu API w Apps Script, rozważ usunięcie go z kodu.
  4. Jeśli nie możesz znaleźć obejścia ani usunąć tego interfejsu API z kodu, a makro generuje ten błąd, nie możesz go przekonwertować.

Przykłady niezaimplementowanych błędów interfejsu API

Oto przykłady niezaimplementowanych problemów z interfejsem API i sposoby ich rozwiązywania:

  • Nie ma odpowiednika Apps Script: pokazuje pośrednie obejście problemu Chart.Protect, czyli interfejsu API, który nie istnieje w Apps Script.
  • Nieznany typ obiektu: pokazuje, jak obsługiwać typ obiektu, który jest zmienną, i jak wdrożyć nieobsługiwany typ obiektu, który można odtworzyć w Apps Script.
Przykład 1. Brak odpowiednika Apps Script lub nieznany interfejs API

W tym przykładzie tabela Chart.Protect nie została automatycznie skonwertowana, ponieważ nie ma sposobu, aby chronić wykres 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 zabezpieczyć wykresu, możesz włączyć ochronę zakresu danych na wykresie, tak aby danych nie można było zmienić.

Poniżej znajdziesz 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

Gdy typ obiektu jest nieznany, do pliku variant_resolution.gs jest dodawany niezaimplementowany błąd interfejsu API. Poniższy przykład rozwija przykład interfejsu VBA name() API. Zobacz variant_resolution.gs.

Z tego przykładu dowiesz się:

  1. Jak interfejs API name() jest konwertowany na nową funkcję w pliku variant_resolution.gs.
  2. Sposób wywoływania nowej funkcji w skonwertowanym kodzie.
  3. Jak utworzyć obejście problemu CommandBar (nieobsługiwanego typu obiektu) w Apps Script

1. Przekonwertowany kod nie może określić dokładnego typu obiektu, który jest wywoływany przez funkcję name(), dlatego konwerter makr tworzy nową funkcję o nazwie __handle_resolve_name, którą widać 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 określa funkcję PrintName(), która wywołuje interfejs API name(). Kod VBA znajduje się poniżej:

‘Defining a function that prints the name of the object in parameter
Sub PrintName(obj as Variant)
  Debug.Print obj.Name
End Sub
Funkcja „name()” jest wywoływana w przypadku obiektu, który jest zmienną, więc przekonwertowany kod nie zna typu obiektu w chwili konwersji. Przekonwertowany 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 typu obiektu CommandBar. Kod VBA znajduje się poniżej:

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

Aby uruchomić nowe funkcje:

3.1 Zdefiniuj nowy typ obiektu, który tworzy funkcje CommandBars i nowy zbiór CommandBars podobny do tego w VBA.

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

Kroki 3.1 i 3.2 są widoczne w kodzie poniżej. Obiekty menu są tworzone za pomocą nowego typu obiektu, który naśladuje działanie 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 Zmodyfikuj funkcję __handle_resolve_name w pliku variant_resolution.gs, aby obsługiwała nowy typ obiektu. Dodaj sekcję do funkcji, 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 dwie funkcje utworzone w pliku unimplemented_constructs.gs (_api_application_commandbars(), _api_commandbars_item()). Dzięki temu pierwotne 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);
}

Niezaimplementowane konstrukcje językowe

construct to element języka kodu, który steruje przepływem wykonywania lub wyświetlaniem danych. Na przykład pętle, etykiety, zdarzenia i goto. Oto lista wszystkich konstrukcji VBA.

Konstrukcje, których nie można przekonwertować przez makrokonwerter, są uznawane za niezaimplementowane konstrukcje językowe.

Gdy konwerter makr ustali, że istnieje niezaimplementowany konstrukt językowy, wstawia komentarz TODO.

Te konstrukcje VBA nie są obsługiwane:

Poprawianie błędów tworzenia niezaimplementowanych języków

  1. Zaktualizuj kod tak, aby Twoja logika nie opierała się na nieobsługiwanej konstrukcji języka.
  2. Otwórz przekonwertowany kod Apps Script w miejscu, w którym wystąpił błąd. Zobacz Znajdowanie błędów.
  3. Kierując się logiką kodu, zaktualizuj go w taki sposób, aby nie wymagał użycia nieobsługiwanego obiektu językowego.
  4. Jeśli nie możesz przeredagować kodu bez nieobsługiwanej konstrukcji języka, nie możesz przekonwertować tego makra.

Przykłady błędów konstrukcji języka w niezaimplementowanym języku

Jednym z najpowszechniejszych konstrukcji językowych, które nie są zaimplementowane, jest wyrażenie GoTo. Niektóre instrukcje GoTo VBA można zastąpić pętlami. Poniżej znajdziesz dwa przykłady użycia pętli zamiast instrukcji GoTo.

Przykład 1. Zastąp GoTo wartością 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
Równoważny kod 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 wartości GoTo wartością „Dla pętli”

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
Równoważny kod 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 przez Apps Script, a inne nie.

Na przykład do definiowania legendy na wykresie programu Excel służy interfejs VBA API legend_position. Obsługuje wiele typów wartości wejściowych, między innymi:

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

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

  • xlLegendPositionCorner
  • xlLegendPositionCustom

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

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

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

Ta 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 częściowo obsługiwanych błędów interfejsu API

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

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

Przykład częściowo obsługiwanego błędu interfejsu API

Poniższy przykład rozwija wspomniany powyżej interfejs VBA API legend_position. Zobacz Częściowo obsługiwany interfejs API.

Poniżej znajdziesz przykład oryginalnego kodu VBA z nieobsługiwaną wartością xlLegendPositionCustom.

Charts(1).Legend.Position = xlLegendPositionCustom

Konwersja makr dodaje poniższą funkcję do pliku 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);
}

Potrzebna jest praca ręczna

Wymagana praca ręczna oznacza, że interfejs VBA API można przekonwertować na język Apps Script, ale jest to sposób obejścia problemu.

W raporcie zgodności wygenerowanym przed konwersją ten typ interfejsu API jest oznaczony jako Obsługiwane z sposobami obejścia problemu.

Jeśli przed przekonwertowaniem pliku nie poprawisz tego typu interfejsu API w kodzie VBA, w projekcie Apps Script będzie to wyglądało tak:

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

Naprawianie błędów związanych z koniecznością pracy ręcznej

Zaimplementuj obejście interfejsu API, aby umożliwić jego prawidłowe działanie. 1. Otwórz przekonwertowany kod Apps Script w miejscu, w którym wystąpił błąd. Zobacz Znajdowanie błędów. 1. Przeczytaj komentarz powyżej funkcji, aby dowiedzieć się, których interfejsów API można użyć w celu obejścia tego problemu. 1. Jeśli nie możesz znaleźć odpowiedniego obejścia, rozważ usunięcie interfejsu API z kodu. 1. Jeśli nie możesz znaleźć obejścia lub usunąć tego interfejsu API z kodu, a makro generuje błąd, nie możesz go przekonwertować.

Przykłady błędów związanych z wymaganą pracą manualną

Oto przykłady interfejsów API, które powodują błędy związane z pracą ręczną, oraz sposoby ich naprawy:

Przykład 1: Autocorrect.Addreplacement

W poniższym przykładzie można przekonwertować interfejs VBA API Autocorrect.Addreplacement, ale wymaga to obejścia. Makro Konwerter sugeruje, jak zaimplementować tę 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.');

}

Implementację interfejsu API Autocorrect.Addreplacement pokazano poniżej:

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 VBA API workbook.open() otwiera plik lokalny na podstawie ścieżki pliku.

Załóżmy, że w kodzie VBA są 2 pliki otwierane przez użytkownika workbook.open():

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

Poniżej pokazujemy, jak konwerter makr zastępuje Workbook.open() skryptem Google Apps Script wszędzie tam, gdzie używany jest Workbook.open() do otwierania pliku 1:

var spreadSheetId =
   _handle_mso_excel_get_google_spreadsheet_id("C:\Data\abc.xlsx");
var spreadSheet = SpreadsheetApp.openById(spreadSheetId);
Ten błąd jest dodawany do pliku unimplemented_constructs.gs w projekcie 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 '';
}

Zgodnie z komentarzami w przykładzie powyżej musisz przekonwertować pliki docelowe na pliki Arkuszy Google na Dysku Google.

Odpowiednie identyfikatory arkuszy kalkulacyjnych Google są pogrubione poniżej:

  • Plik 1: C:\Data\abc.xlsx zmienia się na https://docs.google.com/spreadsheets/d/abc123Abc123Abc123abc
  • Plik 2: C:\Data\abc.xlsx zmienia wartość 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";
 }

Zamierzony błąd

Błędy zamierzone są dodawane do przekonwertowanego kodu, aby naśladować zachowanie oryginalnego kodu VBA. Nie musisz modyfikować tych błędów.

Przykład zamierzonego błędu

Jeśli próbujesz uzyskać dostęp do elementu poza granicami tablicy w języku VBA, kod zgłasza wyjątek. W Apps Script kod zwraca wartość nieokreśloną.

Aby uniknąć nieoczekiwanych wyników, narzędzie do konwertowania makr dodaje kod Apps Script, który zgłasza wyjątek przy próbie dostępu do elementów spoza tablicy.

Oto przykład:

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
Dodano kod Apps Script do zgłaszania błędu wyjątku
/**
* 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));