Naprawianie błędów w przekonwertowanym kodzie

Dodatek Macro Converter automatyzuje większość procesu konwersji, ale finalizacja kodu może wymagać wprowadzenia zmian w niektórych interfejsach API i innych elementach.

W tym przewodniku znajdziesz informacje o plikach Apps Script (pliki GS) dodanych do Twojego projektu, interpretowaniu różnych typów błędów i sposobie ich naprawiania.

Informacje o plikach Apps Script dodanych do projektu

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

  • Zdefiniuj stałe i wartości VBA, których nie ma w Apps Script.
  • Wdrażanie interfejsów API, które nie zostały przekonwertowane.
  • Rozwiąż warianty.

Do projektu Apps Script są dodawane te pliki GS:

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

Library.gs

Nie musisz niczego modyfikować w pliku library.gs.

Plik library.gs definiuje funkcje i stałe, które zostały użyte w kodzie VBA, których nie ma w Apps Script. Dzięki temu nowy kod Apps Script bardziej przypomina kod VBA. Nie musisz też 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ć za pomocą konwertera makr. Prawdopodobnie musisz 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 użyto oryginalnego interfejsu API.

Jeśli znajdziesz obejście, które pozwoli odtworzyć pierwotny interfejs API, musisz tylko zaktualizować definicję funkcji w pliku unimplemented_constructs.gs. Gdy zdefiniowana funkcja będzie tam zdefiniowana, będzie stosowana wszędzie tam, gdzie występuje w projekcie Apps Script.

Oto przykład w kodzie:

Oryginalny kod VBA

Window.activate()

Przekonwertowany kod Apps Script, dodany w tekście

_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

Jeśli nie można określić typu obiektu, do projektu Apps Script jest dodawany plik variant_resolutions.gs. Może się tak zdarzyć z wielu powodów, np. gdy interfejs API ma wiele zwracanych typów 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>(), by 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 Apps Script jest getName(), ale nie dla każdego typu obiektu. Możliwych jest kilka alternatywnych przypadków:

  • Odpowiednik API tego obiektu jest nazywany czymś innym niż getName().
  • Obiekt nie ma interfejsu Apps Script API umożliwiającego pobranie jego nazwy.
  • Nie ma odpowiednika obiektu Apps Script.

Gdy typ obiektu nie zostanie 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 dla bieżącego wyboru. Możesz wybrać obiekt Sheet lub obiekt shape. W przypadku obiektu Sheet tłumaczenie to getName(), ale gdy obiekt jest obiektem kształtu, nie ma jego odpowiednika w Apps Script.

Przekonwertowany kod Apps Script, dodany w tekście

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

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

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

Znajdź błędy

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

W domyślnym środowisku wykonawczym V8 pojawi się 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, znaku 3.

Jeśli korzystasz z wycofanego ś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 możesz naprawić w plikach unimplemented_constructs.gs i variant_resolution.gs opisanych powyżej.

Typy błędów, które mogą wystąpić, obejmują:

Niezaimplementowany interfejs API

Niezaimplementowany interfejs API to interfejs API, którego edytor makr nie może przekonwertować z języka VBA na Apps Script. Nie jest znane obejście tego problemu.

Niezaimplementowane interfejsy API są zazwyczaj dodawane do pliku unimplemented_constructs.gs jako puste funkcje (czasami z pustymi podpisami). Jeśli nie można określić typu obiektu, można zamiast tego dodać do pliku variant_resolution.gs niezaimplementowany interfejs API.

W raporcie zgodności wygenerowanym przed konwersją ten interfejs API jest oznaczony jako Wymaga dodatkowego sprawdzenia.

Jeśli nie naprawisz tego typu interfejsu API w kodzie VBA przed przekonwertowaniem pliku, w projekcie Apps Script będzie on widoczny w następujący sposób:

/**
* 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 niezaimplementowanych błędów interfejsu API

Zdefiniuj niezaimplementowany interfejs 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 błędu. Patrz sekcja Znajdowanie błędów.
  2. Przeczytaj dodany komentarz nad funkcją. W niektórych przypadkach w komentarzu sugerujemy, jak wdrożyć ten interfejs API w Apps Script.
  3. Jeśli nie możesz wdrożyć tego interfejsu API w Apps Script, rozważ usunięcie go z kodu.
  4. Jeśli nie możesz znaleźć obejścia lub usunąć tego interfejsu API z kodu, a Twoje makro zgłasza ten błąd, nie możesz przekonwertować tego makra.

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

Oto przykłady niezaimplementowanych scenariuszy interfejsu API oraz sposoby ich rozwiązania:

  • Brak odpowiednika Apps Script: zawiera pośrednie obejście dla Chart.Protect – interfejsu API, którego nie ma w Apps Script.
  • Nieznany typ obiektu: pokazuje, jak obsługiwać typ obiektu, który jest zmienny, i jak zaimplementować nieobsługiwany typ obiektu, który można odtworzyć w Apps Script.
Przykład 1. Brak odpowiednika Apps Script lub nieznanego interfejsu API

W tym przykładzie wykres Chart.Protect nie został automatycznie przekonwertowany, ponieważ nie ma sposobu ochrony 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.');
}
Mimo że nie możesz chronić wykresu, możesz chronić jego zakres danych, aby nie można było ich zmienić.

Poniżej znajduje się przykładowa implementacja 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 dodawany jest niezaimplementowany błąd interfejsu API. Poniżej znajduje się rozwinięcie powyższego przykładu interfejsu VBA name() API. Zobacz variant_resolution.gs.

Z tego przykładu dowiesz się:

  1. Jak interfejs name() API 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 dla nieobsługiwanego typu obiektu CommandBar w Apps Script.

1. Przekonwertowany kod nie może określić dokładnego typu obiektu, który zostanie wywołany przez funkcję name(), więc konwerter makr tworzy nową funkcję o nazwie __handle_resolve_name widoczną 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 znajdziesz 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
Metoda „name()” jest wywoływana dla obiektu, który jest zmienną, więc przekonwertowany kod nie zna typu obiektu w momencie konwersji. Przekonwertowany kod Apps Script wywoła funkcję `__handle_resolve_name`:
function PrintName(obj) {
  Logger.log(_handle_resolve_name(obj));
}

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

PrintName Application.CommandBars.item("Standard")
Apps Script nie obsługuje metody CommandBar, dlatego 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.
Ten typ obiektu nie jest obsługiwany w Apps Script, dlatego przekonwertowany kod tworzy w pliku „unimplemented_constructs.gs” podane niżej funkcje, które musisz zdefiniować.
  • _api_application_commandbars()
  • _api_commandbars_item()
W skonwertowanym kodzie są wywoływane te funkcje, jak pokazano poniżej:
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 nowego zbioru obiektów CommandBars podobnego do tego, który istnieje w VBA.

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

W poniższym kodzie pokazane są kroki 3.1 i 3.2. Obiekty menu są tworzone jako nowy typ 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 w ten sposób:

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 poprzednie 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 gotos. Oto lista wszystkich konstrukcji VBA.

Konstrukcje, których nie może wykonać konwerter makr, są uznawane za niezaimplementowane konstrukcje językowe.

Gdy konwerter makr ustali, że istnieje niezaimplementowany konstrukcja językowa, wstawia komentarz TODO.

Te konstrukcje VBA nie są obsługiwane:

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

  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 błędu. Patrz sekcja Znajdowanie błędów.
  3. Zależnie od logiki kodu zaktualizuj go w taki sposób, aby nie wymagał nieobsługiwanego konstruktora językowego.
  4. Jeśli nie możesz zmienić kodu bez obsługi nieobsługiwanej konstrukcji języka, nie możesz przekonwertować tego makra.

Przykłady niezaimplementowanych błędów konstrukcji języka

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

Przykład 1. Zastąp GoTo elementem 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 GoTo słowem 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
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 Apps Script, a inne nie.

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

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

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

  • xlLegendPositionCorner
  • xlLegendPositionCustom

Aby oznaczyć w przekonwertowanym kodzie nieobsługiwane wartości częściowo obsługiwanych interfejsów API, do pliku library.gs, który sprawdza te wartości, dodawany jest warunek weryfikacji. 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).

Funkcja zwraca 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 problemu zgodnym z Twoimi potrzebami.

  1. Otwórz przekonwertowany kod Apps Script w miejscu błędu. Patrz sekcja 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 obsługiwane wartości mogą zastąpić te wartości.
  4. Zaktualizuj funkcję _handle_<API_name>_error, aby zwracała obsługiwaną wartość.
  5. Jeśli nie możesz zastąpić nieobsługiwanej wartości, nie możesz przekonwertować tego makra.

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

Poniższy przykład stanowi rozwinięcie interfejsu API VBA legend_position. Zobacz Częściowo obsługiwany interfejs API.

Poniżej znajdziesz przykład oryginalnego kodu VBA, który wykorzystuje nieobsługiwaną wartość: xlLegendPositionCustom.

Charts(1).Legend.Position = xlLegendPositionCustom

Konwerter makr dodaje do pliku unimplemented_constructs.gs poniższą 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);
}

Wymaga pracy ręcznej

Wymagana ręczna praca oznacza, że interfejs VBA API można przekształcić w Apps Script, ale wymaga to obejścia.

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

Jeśli nie naprawisz tego typu interfejsu API w kodzie VBA przed przekonwertowaniem pliku, w projekcie Apps Script będzie on widoczny w następujący sposób:

/**
* 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 wymaganą pracą ręczną

Wprowadź obejście dla interfejsu API, aby zapewnić jego prawidłowe działanie. 1. Otwórz przekonwertowany kod Apps Script w miejscu błędu. Zobacz Znajdowanie błędów. 1. Przeczytaj komentarz nad funkcją, aby dowiedzieć się, których interfejsów API można użyć, aby obejść ten problem. 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 Twoje makro zwróci błąd, nie możesz przekonwertować tego makra.

Przykłady błędów związanych z pracą ręczną

Oto przykłady interfejsów API, które zgłaszają błędy wymagające ręcznej pracy, oraz sposoby ich naprawy:

Przykład 1: Autocorrect.Addreplacement

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

}

Implementacja interfejsu API Autocorrect.Addreplacement została przedstawiona 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 program workbook.open() otwiera 2 pliki:

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

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

var spreadSheetId =
   _handle_mso_excel_get_google_spreadsheet_id("C:\Data\abc.xlsx");
var spreadSheet = SpreadsheetApp.openById(spreadSheetId);
Ten błąd pojawia się w 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 powyższym przykładzie 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 zmieni się na https://docs.google.com/spreadsheets/d/abc123Abc123Abc123abc
  • Plik 2: C:\Data\abc.xlsx zmieni 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";
 }

Zamierzony błąd

Do przekonwertowanego kodu są dodawane zamierzone błędy, aby naśladować działanie błędu oryginalnego kodu VBA. Nie musisz modyfikować tych błędów.

Przykład celowego błędu

Jeśli spróbujesz uzyskać dostęp do elementu wykraczającego poza granice tablicy w VBA, kod zwróci wyjątek. W Apps Script kod zwraca wartość niezdefiniowaną.

Aby uniknąć nieoczekiwanych wyników, konwerter makr dodaje kod Apps Script, który zgłasza wyjątek w przypadku próby uzyskania dostępu do elementów poza granicami tablicy.

Ten przykład widać w poniższym kodzie:

Oryginalny kod VBA
Dim arr
arr = Array("apple", "orange")
MsgBox arr(5)
Will throw the following error:
Subscript out of range
Kod Apps Script do konwersji (przed dodaniem błędu dotyczącego 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 powodujący błąd 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));